React生命周期学习

useState

用法:const [state, setState] = useState(initialState);

initialState:state的初始值

setState:用于更新state的值,它接收一个新的state值并将组件的一次重新渲染加入队列,在后续渲染中useState返回的第一个值将始终是更新后最新的state

1、如果新的state需要通过使用先前的state计算得出,那么可以将函数传递给setState。该函数将接收先前的state,并返回一个更新后的值

function Counter({initialCount}) {
  const [count, setCount] = useState(initialCount);
  return (
    <>
      Count: {count}
      <button onClick={() => setCount(initialCount)}>Reset</button>
      <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
      <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
    </>
  );
}
复制代码

2、如果初始state需要通过复杂计算获得,则可以传入一个函数,在函数中计算并返回初始的state,此函数只在初始渲染时被调用

const [state, setState] = useState(() => {
  const initialState = someExpensiveComputation(props);
  return initialState;
});
复制代码

useEffect

1、在函数体内执行有其他副作用的操作都是不被允许的,因为会产生莫名其妙的bug并且会破坏UI的一致性。

2、默认情况下,effect将在每轮渲染结束后执行,这样的话,一旦effect的依赖发生变化,它就会被重新创建。但你也可以选择让它在只有某些值改变的时候才执行。

3、虽然useEffect会在浏览器绘制后延迟执行,但会保证在任何新的渲染前执行。在开始新的更新前,React总会先清除上一轮渲染的effect。

4、useEffect最后,不加[]就表示每一次渲染都执行,用来替代willUpdate等每次渲染都会执行的生命函数

useEffect(()=>{
    const users = 每次都获取全国人民的信息()
})
复制代码

5、useEffect最后,加了[]就表示只第一次执行,类似于componentDidMount

useEffect(()=>{
    const users = 获取全国人民的信息()
},[])
复制代码

6、useEffect最后,加[],并且[]里面加的字段就表示,这个字段更改了,我这个effect才执行

useEffect(() => {
    const users = (name改变了我才获取全国人民的信息())
},[name])
复制代码

6、我们不需要在每次组件更新时都创建新的订阅,而是仅需要在source prop改变时重新创建。要实现这一点,可以给useEffect传递第二个参数,它是effect所依赖的值数组。在effect的return里面可以做取消订阅的事,类似于willUnMount

useEffect(
  () => {
    const subscription = props.source.subscribe();
    return () => {
      subscription.unsubscribe();
    };
  },[props.source]);   //此时,只有当props.source改变后才会重新创建订阅
复制代码

注意:如果你要使用此优化方式,请确保数组中包含了所有外部作用域中会发生变化且在effect中使用的变量,否则你的代码会引用到先前渲染中的旧变量。请记得React会等待浏览器完成画面渲染之后才会延迟调用useEffect。

7、规则细节

1)useEffect 里面使用到的state的值, 固定在了useEffect内部, 不会被改变,除非useEffect刷新,重新固定state的值

 const [count, setCount] = useState(0)
    useEffect(() => {
        console.log('use effect...',count)
        const timer = setInterval(() => {
            console.log('timer...count:', count)
            setCount(count + 1)
        }, 1000)
        return ()=> clearInterval(timer)
    },[])
复制代码

2)useEffect不能被判断包裹

const [count, setCount] = useState(0)
if(2 < 5){
   useEffect(() => {
        console.log('use effect...',count)
        const timer = setInterval(() => setCount(count +1), 1000)
        return ()=> clearInterval(timer)
    }) 
}
复制代码

useMemo

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
复制代码

1、把“创建”函数和依赖项数组作为参数传入useMemo,它仅会在某个依赖项改变时才重新计算memoized值,这种优化有助于避免在每次渲染时都进行高开销的计算。

2、传入useMemo的函数会在渲染期间执行,请不要在这个函数内部执行与渲染无关的操作,诸如副作用这类的操作属于useEffect的适用范畴,而不是useMemo。

3、先根据[name]里面的name值判断一下,因为useMemo 作为一个有着暂存能力的,暂存了上一次的name结果。对比上一次的name,我们发现name值没有改变,那么这次data就不重新赋值成新的对象了!

  const data = useMemo(()=>{
        return {
            name
        }
    },[name])
复制代码

4、React.memo和useMemo的区别:如果函数组件被 React.memo 包裹,且其实现中拥有useState或useContext的Hook,当context发生变化时,它仍会重新渲染。memo是浅比较,对象只比较内存地址,只要你内存地址没变,管你对象里面的值千变万化都不会触发render,于是就需要使用到useMemo。useMemo解决值的缓存。

useRef

useEffect里面的state的值,是固定的,这个是有办法解决的,就是用useRef,可以理解成useRef的一个作用:

1、就是相当于全局作用域,一处被修改,其他地方全更新…

 const [count, setCount] = useState(0)
 const countRef = useRef(0)
useEffect(() => {
    console.log('use effect...',count)
    const timer = setInterval(() => {
        console.log('timer...count:', countRef.current)
        setCount(++countRef.current)
    }, 1000)
    return ()=> clearInterval(timer)
},[])
复制代码

2、普遍操作,用来操作dom

const refContainer = useRef(initialValue);
复制代码

useRef 返回一个可变的ref对象,其.current属性被初始化为传入的参数(initialValue)。返回的ref对象在组件的整个生命周期内保持不变。

function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () => {
    // `current` 指向已挂载到 DOM 上的文本输入元素
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}
复制代码

本质上,useRef就像是可以在其.current属性中保存一个可变值的“盒子”,useRef()比ref属性更有用。它可以很方便地保存任何可变值,useRef()和自建一个{current: …}对象的唯一区别是,useRef会在每次渲染时返回同一个ref对象。

useCallback

1、useMemo是缓存值的,而useCallback是缓存函数

2、没有依赖,添加空的依赖,就是空数组

   const onChange = useCallback((e)=>{
        setText(e.target.value)
   },[])
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享