React Hooks 初上手
为什么要用hooks
- Hook是React16.8的新增特性
- 编写class组件逻辑比较简单,但是业务增多,class组件就会越来越复杂(hook解耦性更强)
- 繁琐的生命周期代替
了解项目中常用的hooks
- useState
const [state, setState] = useState(initialState);
// 需要传入一个参数作为状态的初始值,当函数执行后会返回两个值,一个是当前状态的属性,一个是修改状态的方法。
// 值的改变能驱动视图的更新,但只能通过setState 赋值
// 有点像 vue3 的 const state = ref(0)
// setState 是对原有值的覆盖 所以每次都以赋值的形式
const [state, setState] = useState({a:1,b:2});
setState((pre)=>{
return {
...pre,
b: 45,
}
})
//(setState是异步执行 也不接受await)
- useEffect
(最难理解的钩子)
该 Hook 接收一个包含命令式、且可能有副作用代码的函数
//对一个值的副作用作为依赖监听 当 count 变化时就会触发副作用
const [count, setCount] = useState(0)
useEffect(() => {
console.log("useEffect:", count)
},[count])
//可以对多个值进行依赖监听
const [count, setCount] = useState(0)
const [state, setState] = useState({a:1,b:2})
useEffect(() => {
console.log("useEffect:", count,state)
},[count,state.a])
//代替生命周期 数组为空组件初始化只会触发一次 ,return的函数组件销毁的时候触发,一般用于清除定时器等
const getList = async () => {
await axios
}
useEffect(() => {
getList()
const timeInterval = setInterval(()=>{
console.log('react真难用')
},3000)
return ()=>{
clearInterval(timeInterval)
}
},[])
注意:1. 添加错误的依赖会造成重复的执行副作用。2. 副作用内不能重新赋值造成无限循环。
useEffect的依赖数组是最容易造成报错的原因。
- useCallback
//传入一个回调函数,依赖更新才会返回一个新的函数
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
用的比较少,也很容易出现bug,主要用在性能优化
- useMemo
(计算属性类似vue2 computed)
const [count, setCount] = useState(1)
//useMemo通过对依赖的计算 返回一个值
const moreCount = useMemo(() => {
return count + 100
},[count])
//useMemo也可以通过对依赖的计算返回一个函数(类似useCallback)
const fnCount = useMemo(() => {
return ()=>{
if(count == 1){
console.log('react真好用')
}else{
console.log('react真难用')
}
}
},[count])
如果没有提供依赖项数组,useMemo 在每次渲染时都会计算新的值。
- useRef、forwardRef、useImperativeHandle
可以获取元素真实节点或者组件的实例 类似 Vue2的 this,$refs.AFormRef
// useRef + forwardRef 自定义组件这两个必须一起用
//parent.jsx
const AFormRef = useRef();
......
<AForm ref={AFormRef} {...formProps} />
//forwardRef导出的组件可以通过useRef拿到 但只有dom
//child.jsx
React.forwardRef(function AForm(props, ref) {
return (
<div ref={ref}>
<Form form={form} {...formLayout}>
{initFromItem()}
</Form>
</div>
);
})
// useRef + forwardRef + useImperativeHandle
//parent.jsx
const AFormRef = useRef();
......
<AForm ref={AFormRef} {...formProps} />
//child.jsx
React.forwardRef(function AForm(props, ref) {
const formRef = useRef();
useImperativeHandle(ref, () => ({
getForm: () => {
return 123
},
formRef:formRef,
}))
return (
<div ref={ref}>
<Form ref={formRef} form={form} {...formLayout}>
{initFromItem()}
</Form>
</div>
);
})
一般获取子组件组件实例和它的方法、或者dom节点。
非常见、用的少的hooks
- useContext + createContext 爷爷组件向孙子组件传值
- useReducer 组件内用的 redux
- useLayoutEffect 所有的 DOM 变更之后同步调用(慎用容易阻塞视觉更新)
- useDebugValue 可用于在 React 开发者工具中显示自定义 hook 的标签。