概述
文章目录
- 为什么会有Hooks?
- 什么是Hooks?
- 一、userState():状态钩子
- 二、useEffect():副作用钩子
- 三、useContext():共享状态钩子
- 四、useReducer():Action钩子
- 五、创建自己的Hooks
为什么会有Hooks?
首先要说一下React的组件创建方式,一种是类组件,一种是纯函数组件,并且React团队希望,组件不要变成复杂的容器,最好只是数据流的管道。开发者根据需要,组合管道即可。也就是说组件的最佳写法应该是函数,而不是类。
但是我们知道,在以往开发中类组件和纯函数组件的区别是很大的,纯函数组件有着类组件不具备的多种特点,简单列举几条
- 纯函数组件没有状态
- 纯函数组件没有生命周期
- 纯函数组件没有this
- 只能是纯函数
这就注定,我们所推崇的函数组件,只能做UI展示的功能,涉及到状态的管理与切换,我们不得不用类组件或者redux。React团队设计了React Hooks,就是加强版的函数组件,我们可以完全不使用 class,就能写出一个全功能的组件。
什么是Hooks?
'Hooks’的单词意思为“钩子”
React为我们提供了一些常用的钩子,当然有特殊需要,我们也可以写自己的钩子。下面是React为我们提供的默认的四种最常用钩子:
- useState()
- userContext()
- userReducer()
- useEffect()
React约定,钩子一律使用 use前缀命名。所以,你自己定义的钩子都要命名为useXXX。
一、userState():状态钩子
我们知道,纯函数组件没有状态,useState()用于为函数组件引入状态。
实现累加的示例:
import React, {useState} from 'react'
const AddCount = () => {
const [ count, setCount ] = useState(0)
const addcount = () => {
let newCount = count
setCount(newCount+=1)
}
return (
<>
<p>{count}</p>
<button onClick={addcount}>count++</button>
</>
)
}
export default AddCount
通过上面的代码,我们实现了一个功能完全一样的计数器,代码看起来更加的轻便简洁,没有了继承,没有了渲染逻辑,没有了生命周期等。这就是hooks存在的意义。
在useState()中,它接受状态的初始值作为参数,即上例中计数的初始值,它返回一个数组,其中数组第一项为一个变量,指向状态的当前值。类似this.state,第二项是一个函数,用来更新状态,类似setState。该函数的命名,我们约定为set前缀加状态的变量名。
二、useEffect():副作用钩子
useEffect(() => {},[array])
useEffect()接受两个参数,
- 第一个参数是函数,第二个参数是一个数组,用来给出Effect的依赖项。只要这个数组发生变化,useEffect()就会执行。这是监听数据变化。
- 当第二项省略不填时,useEffect()会在每次组件渲染时执行。这一点类似于类组件的componentDidMount,初始化渲染。
下面的示例,有第二个参数,useEffect()依赖第二项数组变化而调用
import React, { useState, useEffect } from 'react'
const AsyncPage = ({name}) => {
const [loading, setLoading] = useState(true)
const [person, setPerson] = useState({})
useEffect(() => {
setLoading(true)
setTimeout(()=> {
setLoading(false)
setPerson({name})
},2000)
},[name])
return (
<>
{loading?<p>Loading...</p>:<p>{person.name}</p>}
</>
)
}
const PersonPage = () =>{
const [state, setState] = useState('')
const changeName = (name) => {
setState(name)
}
return (
<>
<AsyncPage name={state}/>
<button onClick={() => {changeName('名字1')}}>名字1</button>
<button onClick={() => {changeName('名字2')}}>名字2</button>
</>
)
}
export default PersonPage
下面的示例,无第二个参数,只是挂载时调用
import React, { useState, useEffect } from 'react'
const AsyncPage = () => {
const [loading, setLoading] = useState(true)
useEffect(() => {
// 没有第二个参数,则只是挂载时调用
setTimeout(()=> {
setLoading(false)
},5000)
})
return (
loading ? <p>Loading...</p>: <p>异步请求完成</p>
)
}
export default AsyncPage
上面代码中,通过改变传给AsyncPage的props,从而调用useEffect()
三、useContext():共享状态钩子
该钩子的作用是,在组件之间共享状态。其作用就是可以做状态的分发,在React16.X以后支持,避免了react逐层通过Props传递数据。
下面是一个例子,现在假设有A组件和B组件需要共享一个状态。
import React,{ useContext } from 'react'
const Ceshi = () => {
const AppContext = React.createContext({})
//A组件
const A =() => {
const { name } = useContext(AppContext)
return (
<p>我是A组件的名字{name}<span>我是A的子组件{name}</span></p>
)
}
//B组件
const B =() => {
const { name } = useContext(AppContext)
return (
<p>我是B组件的名字{name}</p>
)
}
return (
<AppContext.Provider value={{name: 'hook测试'}}>
<A/>
<B/>
</AppContext.Provider>
)
}
export default Ceshi
可以看到,我们可以通过hooks做状态的共享。
四、useReducer():Action钩子
我们知道,在使用React的过程中,如遇到状态管理,我们一般会用到Redux,而React本身是不提供状态管理的。而useReducer()为我们提供了状态管理。
首先,关于redux我们都知道,其原理是我们通过用户在页面中发起action,从而通过reducer方法来改变state,从而实现页面和状态的通信。
而Reducer的形式是(state, action) => newstate。类似,我们的useReducer()是这样的
const [state, dispatch] = useReducer(reducer, initialState)
它接受reducer函数和状态的初始值作为参数,
返回一个数组,其中第一项为当前的状态值,第二项为发送action的dispatch函数
。下面我们依然用来实现一个计数器。
和redux一样,我们是需要通过页面组件发起action来调用reducer方法,从而改变状态,达到改变页面UI的这样一个过程。所以我们会先写一个Reducer函数,然后通过useReducer()返回给我们的state和dispatch来驱动这个数据流。思路就是这样,下面我们上代码
import React,{useReducer} from 'react'
const AddCount = () => {
//创建一个reducer
const reducer = (state, action) =>
{
if(action.type === ''add){
return {
...state,
count: state.count +1,
}
}else {
return state
}
}
const addcount = () => {
dispatch({
//触发reducer中相应的操作
type: 'add'
})
}
//创建一个reducer
const [state, dispatch] = useReducer(reducer, {count: 0})
return (
<div>
<p>{state.count}</p>
<button onClick={addcount}>count++</button>
</div>
)
}
export default AddCount
通过代码我们看到了,我们使用useReducer()代替了Redux的功能,但useReducer无法为我们提供中间件等功能,假如你有这些需求,还是需要用到redux。
五、创建自己的Hooks
React提供给我们的默认React Hooks,有时候我们需要创建我们自己想要的Hooks,来满足更便捷的开发,在小编看来,无非就是根据业务场景对以上四种Hooks进行组装,从而得到满足自己需求的钩子。
比如,我们要将我们上面的代码功能封装成Hooks:
import React, { useState, useEffect } from 'react'
//自定义hooks
const usePerson = (name) => {
const [loading, setLoading] = useState(true)
const [person, setPerson] = useState({})
useEffect(() => {
setLoading(true)
setTimeout(()=> {
setLoading(false)
setPerson({name})
},2000)
},[name])
return [loading,person]
}
//函数组件使用自定义的hooks
const AsyncPage = ({name}) => {
const [loading, person] = usePerson(name)
return (
<>
{loading?<p>Loading...</p>:<p>{person.name}</p>}
</>
)
}
//函数组件使用自定义的hooks
const PersonPage = () =>{
const [state, setState]=useState('')
const changeName = (name) => {
setState(name)
}
return (
<>
<AsyncPage name={state}/>
<button onClick={() => {changeName('名字1')}}>名字1</button>
<button onClick={() => {changeName('名字2')}}>名字2</button>
</>
)
}
export default PersonPage
上面代码中,我们将之前的例子封装成了自己的Hooks,便于共享。其中,我们定义usePerson()为我们的自定义Hooks,它接受一个字符串,返回一个数组,数组中包括两个数据的状态,之后我们在使用usePerson()时,会根据我们传入的参数不同而返回不同的状态,然后很简便的应用于我们的页面中。
作者:Nosaj
链接:https://www.jianshu.com/p/d600f749bb19
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
最后
以上就是开心草丛为你收集整理的React Hooks 详解为什么会有Hooks?什么是Hooks?的全部内容,希望文章能够帮你解决React Hooks 详解为什么会有Hooks?什么是Hooks?所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复