react hooks的缺点,针对状态不同步和没有生命周期

react在16.8中加入了hooks,可以在函数组件中添加一些有自己独立上下文管理的状态(useState),不再依赖于类组件,同时一些逻辑也可以放到hooks中来复用(useEffects)。

不巧,最近react项目里用到了hooks,就拿来练练手,在开发中遇到了点问题,我就说说我的问题和解决方案吧

1.没有生命周期。

2.没有回调函数。

缺点

一、状态不同步

函数的运行是独立的,每个函数都有一份独立的作用域。函数的变量是保存在运行时的作用域里面,当我们有异步操作的时候,经常会碰到异步回调的变量引用是之前的,也就是旧的(这里也可以理解成闭包)如下:

import React, { useState } from "react";
​
const Counter = () => {
  const [counter, setCounter] = useState(0);
​
  const onAlertButtonClick = () => {
    setTimeout(() => {
      alert("Value: " + counter);
    }, 3000);
  };
​
  return (
    <div>
      <p>You clicked {counter} times.</p>
      <button onClick={() => setCounter(counter + 1)}>Click me</button>
      <button onClick={onAlertButtonClick}>
        Show me the value in 3 seconds
      </button>
    </div>
  );
};
​
export default Counter;

当你点击Show me the value in 3 seconds的后,紧接着点击Click me使得counter的值从0变成1。三秒后,定时器触发,但alert出来的是0(旧值),但我希望的结果是当前的状态1。

这时我们可以用useEffect来实现我们的需求

import React, { useState, useRef, useEffect } from "react";
​
const Counter = () => {
  const [counter, setCounter] = useState(0);
  const counterRef = useRef(counter);
​
  const onAlertButtonClick = () => {
    setTimeout(() => {
      alert("Value: " + counterRef.current);
    }, 3000);
  };
​
  useEffect(() => {
    counterRef.current = counter;
  });
​
  return (
    <div>
      <p>You clicked {counter} times.</p>
      <button onClick={() => setCounter(counter + 1)}>Click me</button>
      <button onClick={onAlertButtonClick}>
        Show me the value in 3 seconds
      </button>
    </div>
  );
};
​
export default Counter;

这时alert的是当前的值1。其实解决这个hooks的问题也可以参照类的instance。用useRef返回的immutable RefObject(current属性是可变的)来保存state,然后取值方式从counter变成了: counterRef.current 。

二、没有生命周期

比如我在开发中设置了个定时器,那我想页面销毁的时候肯定要清除定时器。那没有生命周期的hooks怎么实现我们的需求呢。

 //创建一个标识,通用容器
    const timer = useRef(null);
    const onEvent = async (eventName, params) => {
        switch (eventName) {
            case 'updateFileList':
                try {
                    timer.current = setInterval(async () => {
                        await getReferenceBooKData(true, true, setAllocatedMainfestData);//某些循环请求数据的
                    }, 1500);
                } catch (e) {
                    // todo
                }
                return;
           
        }
    }
    useEffect(() => () => { return componentWillUnmount() }, []);
    //销毁组件清除定时器
    const componentWillUnmount = ()=>{
        if (timer.current) {
            clearTimeout(timer.current);
        }
    };

代码不是很全,主要可以参考方法的使用。就这样完美解决了我的问题,相当于监听了页面销毁的componentWillUnmount,如果你有其他需要周期需要操作的,也可以参考下面的用useEffect实现其他的周期变化操作

useEffect( () => console.log("mount"), [] );
useEffect( () => console.log("will update data1"), [ data1 ] );
useEffect( () => console.log("will update any") );
useEffect( () => () => console.log("will update data1 or unmount"), [ data1 ] );
useEffect( () => () => console.log("unmount"), [] );