在箭头功能组件中未更新反应状态值

时间:2020-08-24 04:11:52

标签: reactjs

反应状态值在控制台中未更新,但在视图中已更新。

这是我的完整代码

import React, { useEffect, useState } from 'react';

const Add = (props) => {
    console.log("a = ", props.a)
    console.log("b = ", props.b)
    const c = props.a+props.b;
    return (
        <div>
            <p><b>{props.a} + {props.b} = <span style={{'color': 'green'}}>{c}</span></b></p>
        </div>
    )
}

// export default React.memo(Add);

const AddMemo = React.memo(Add);

const MemoDemo = (props) => {

    const [a, setA] = useState(10)
    const [b, setB] = useState(10)
    const [i, setI] = useState(0);

    
    useEffect(() => {
        init()
        return () => {
            console.log("unmounting...")
        }
    }, [])

    const init = () => {
        console.log("init", i)
        setInterval(()=>{
            console.log("i = ", i)
            if(i == 3){
                setA(5)
                setB(5)
            }else{
                setA(10)
                setB(10)
            }
            setI(prevI => prevI+1)
        }, 2000)
    }

    return (
        <div>
            <h2>React Memo - demo</h2>
            <p>Function returns previously stored output or cached output. if inputs are same and output should same then no need to recalculation</p>
    <b>I= {i}</b>
            <AddMemo a={a} b={b}/>
        </div>    
    );
}   

export default MemoDemo;

请检查这张图片enter image description here

任何人都请解释一下为什么这样工作以及如何解决这个问题

2 个答案:

答案 0 :(得分:1)

问题在于您一次初始化了setInterval,因此它始终会引用初始值i。同时,React总是引用最新的,它总是反映UI上的最新值,而您的时间间隔总是引用旧的。因此解决方案非常简单,只需在每次i更改后取消间隔,即可引用更新后的值:

React.useEffect(() => {
    // re-create the interval to ref the updated value
    const id = init();
    return () => {
      // kill this after value changed
      clearInterval(id);
    };
     // watch the `i` to create the interval
  }, [i]);

  const init = () => {
    console.log("init", i);
    // return intervalID to kill
    return setInterval(() => {
      // ... 
    });
  };

答案 1 :(得分:0)

在传递给setInterval的回调中,您对i=0的值有一个 closure

要对其进行修复,可以使用参考,在功能更新中记录值或使用useEffect

// Recommended
useEffect(() => {
  console.log(i);
}, [i])


const counterRef = useRef(i);
setInterval(()=> {
  // or
  setI(prevI => {
    console.log(prevI+1);
    return prevI+1;
  })

  // or 
  conosole.log(counterRef.current);
}, 2000);