useEffect的四种玩法
useEffect(callBack):
- 第一次渲染完毕后, 执行callback, 等价于类组件的componentDidMount。
- 在组件每次更新完毕后,也会执行callback, 等价于componentDidUpdate。
useEffect(callback,[]):
- 只有第一次渲染完毕后,才会执行callback, 每一次视图更新完毕后, callback不再执行,类似componentDidMount。
- 后面的空数组,无依赖
useEffect(callback,[x]):
- 第一次渲染完毕会执行callback。
- 后面数组里面如果有变量,变量发生变化的时候,callback会执行。类似于监听。
- 后面的数组可以是多个状态,依赖关系,依赖发生变化,callback就会执行,反之,不执行。
useEffect(()=>{return ()=> {}})callback函数里面又返回一个函数,那么这个函数拿到的状态是上一次执行的值,执行时机是,会在组件释放的时候执行。如果组件更新,会把上一次返回的小函数执行,可以理解为上一次渲染的组件释放了的时候执行。
useEffect不能放在循环、判断操作语句中。 useEffect如果有返回值,那么返回的必须是一个函数,代表组件销毁时触发。
useEffect和useLayoutEffect的区别
如果链表中的callback执行又修改了状态值(视图更新),对于useEffect来讲第一次真是dom已经渲染,组件更新会重新渲染真实的dom, 所以频繁切换的时候,会出现样式内容的闪烁.
对于useLayoutEffect来讲,第一次真实dom还未渲染,遇到callback中修改状态,视图立即更新,创建出新的virtualDOM,然后和上次的virtualDOM合并在一起渲染为真实的dom, 也就是此类需求下,真实dom只渲染一次, 不会出现内容样式的闪烁。
- 函数组件中获取ref(前面两种类组件和函数组件都可以,最后一种只能函数组件中使用)
//------方法1
let box = null
<div ref={x => box = x}></div>
//------方法2
let ele = React.createRef()
<div ref={ele}></div>
ele.current //通过current属性获取当前对象
函数组件也有个单独的hooks函数专门用来获取ref的
let box = useRef(null)
<div ref={box}></div>
box.current //通过current属性获取当前对象
React.createRef() 和 useRef(null)区别:
useRef(null) 在组件更新的时候,不会创建新的对象,获取的事第一次创建的那个ref对象
React.createRef()在组件更新的时候会重新创建一个全新的ref对象,比较浪费性能。
在函数组件中推荐useRef,在类组件中使用React.createRef()
子组件是函数组件的时候使用ref需要React.forwardRef()包一层
const Child React.forwardRef(function(props,ref){ return <div className='child-box' ref={ref}></div> })
基于forwardRef实现了ref转发的同时,要获取子组件内部的状态和方法就要借助
useImperativeHandle来暴露const Child React.forwardRef(function(props,ref){ let [text,setText]=useState('hello word') useImperativeHandle(ref,()=>{ return { text // 这样父组件就可以用了 } }) return <div className='child-box' ref={ref}></div> })
- useMemo
let ratio = useMemo(()=>{ let total =supNum + oppNum ratio = '--' if(total > 0) ratio = (supNum / total * 100).toFixed(2) + '%' ratio }, [supNum, oppNum])//当supNum和oppNum发生变化的时候才会执行useMemo的函数
5.useCallback
- 组件第一次渲染,useCallback执行,创建一个函数‘callback’,赋值给xxx
- 组件后续每一次更新,判断依赖的状态是否改变, 如果改变,则重新创建新的函数堆, 赋值给xxx, 但是如果,依赖的状态没有更新或者没有设置依赖, 则xxx的获取的一直是第一次创建的函数堆,不会创建新的函数出来。或者说基于usecallback,可以始终获取第一次创建函数的内存地址
- 父组件嵌套子组件,父组件要把一个内部函数基于属性传递给子组件, 此时传递的这个方法, 我们基于useCallback处理一下会更好。函数子组件就用React.memo(xxx)包裹一下,类子组件就用pureComponent。
6.自定义hooks
- 用usexxx开头,react在编译的时候会自动给你做一下校验,不如不能再if中使用use等,所以自定义hooks推荐用use起头命名