关于react组件传值和获取state的旧值

935 阅读1分钟

1.获取state的旧值 || 上一轮的state或props

公用hook

    import { useRef, useEffect } from 'react';

    // 记录旧值的公用hooks
    export default function usePrevious(value) {
      const ref = useRef();
      useEffect(() => {
        ref.current = value;
      });
      return ref.current;
    }

页面使用

     const [currentMarker, setCurrentMarker] = useState({}); // 当前激活的值
     const prevMarkerRef = usePrevious(currentMarker); // 上一个激活的值
     

原理:

在这里插入图片描述

2.实际演练

需求1:子页面更改全局状态,主页面监听全局状态--HomePage页面和Children2组件

需求2:主页面监听全局状态,调用子页面的方法,类似表单提交,需要注意是否能拿到最新的全局状态----HomePage页面和Children1组件

    import React, {
      useEffect,
      useState,
      forwardRef,
      useImperativeHandle,
      useRef,
    } from 'react';
    import { Button } from 'antd';
    import { useSelector, useDispatch } from 'umi';
    import usePrevious from './demo';  // 封装的保存状态hook

    const Children1 = forwardRef((props, ref) => {
      const datam = useSelector((state) => state.common.textData);
      useImperativeHandle(ref, () => ({
        update: async () => {
          return await childrenClick1();
        },
      }));
      const childrenClick1 = async () => {
        // 能拿到最新的datam
        console.log(datam, 'qwer');
      };

      return <Button></Button>;
    });
    const Children2 = () => {
      const dispatch = useDispatch();

      const childrenClick2 =  () => {
          dispatch({
          type: 'common/saveData',
          payload: '点击测试',
        });
      };
      return <Button onClick={childrenClick2}>Children2</Button>;
    };
    const HomePage = () => {
      const textRef = useRef(null);
      const dispatch = useDispatch();
      const datam = useSelector((state) => state.common.textData); // 获取全局变量
      const [middleState, setMiddleState] = useState(undefined); // 设置中间变量
      const prevMarkerRef = usePrevious(middleState); // 上一个激活的值

      useEffect(() => {
        if (datam) {
          console.log('first') // 全局状态改变时,会触发
          textRef.current.update();
        }
        setMiddleState(datam);
      }, [datam]);

      const handleClick = () => {
        dispatch({
          type: 'common/saveData',
          payload: '主页面',
        });
      };
      return (
        <div>
          <Children1 ref={textRef}></Children1>
          <Children2></Children2>
          <Button onClick={handleClick}>主页面</Button>
        </div>
      );
    };

    export default HomePage;

遇到问题:

错误的
    // 当直接获取全局状态,使用时会拿到最新的值,不是上一个状态
    const prevMarkerRef = usePrevious(datam); 
正确的
    const [middleState, setMiddleState] = useState(undefined); // 设置中间变量
    const prevMarkerRef = usePrevious(middleState); // 上一个激活的值
    //需要在useEffect监听中设置状态
    useEffect(() => {
      setMiddleState(datam);
    }, [datam]);

延伸

当需要获取上一个全局状态时,需要重新设置状态
  useEffect(() => {
    setMiddleState(datam);
  }, [datam]);

参考链接:blog.csdn.net/qq_40593656…