代码之家  ›  专栏  ›  技术社区  ›  Baron Young

如果传递变量而不是显式文本,则React setState hook不会更新依赖元素

  •  2
  • Baron Young  · 技术社区  · 4 年前

    我正处于抛掷反应和使用香草JS的边缘,但我想先检查一下这里。我只是试图将包含对象的变量的内容传递到状态,并让它更新依赖它的元素。如果我向setState传递一个包含对象的变量,它将不起作用。如果我把对象的显式文本传递给它。

    使用React v 18.0.0

        function buttonHandler(e) {
            e.preventDefault()
            let tmpObject = {...chartData}
            tmpObject.datasets[0].data = quoteData.map(entry => entry['3'])
            tmpObject.datasets[1].data = quoteData.map(({fastEma}) => fastEma)
            tmpObject.datasets[2].data = quoteData.map(({slowEma}) => slowEma)
            tmpObject.labels = quoteData.map(entry => new Date(entry.timestamp).toLocaleTimeString())
            console.log("from button:", tmpObject)
            setChartData(prevState => {
                console.log("tmpObject",tmpObject)
                return tmpObject
            })
    
        return <div>
            <button onClick={buttonHandler}>Update</button>
    
            <Line options={chartOptions} data={chartData}/>
        </div>
    

    当我运行上述命令时,控制台的输出。日志与应该的完全相同,但元素不更新。如果我从控制台复制对象输出,并将其显式粘贴到代码中,那么它确实可以工作。

        function buttonHandler(e) {
            e.preventDefault()
            setChartData({...}) 
    

    我尝试了下面陈述中所有可以想象的变化,但都没有用。。。

    return {...prevState, ...tmpObject}
    

    如有任何建议,我将不胜感激。

    编辑:

    <p>{`${new Date().toLocaleTimeString()} {JSON.stringify(chartData)}`</p>
    
    1 回复  |  直到 4 年前
        1
  •  1
  •   Drew Reese    4 年前

    问题在于状态突变。即使你已经复制了 chartData 说明你应该记住这是一份参考副本。每个属性仍然是对原始属性的引用 图表数据 对象

    function buttonHandler(e) {
      e.preventDefault();
    
      let tmpObject = { ...chartData }; // <-- shallow copy ok
      tmpObject.datasets[0].data = quoteData.map(entry => entry['3']); // <-- mutation!!
      tmpObject.datasets[1].data = quoteData.map(({ fastEma }) => fastEma); // <-- mutation!!
      tmpObject.datasets[2].data = quoteData.map(({ slowEma }) => slowEma); // <-- mutation!!
      tmpObject.labels = quoteData.map(
        entry => new Date(entry.timestamp).toLocaleTimeString()
      );
    
      console.log("from button:", tmpObject);
    
      setChartData(prevState => {
        console.log("tmpObject",tmpObject);
        return tmpObject;
      });
    }
    

    在React中,下一个状态不仅需要是一个新的对象引用,而且任何正在更新的嵌套状态都需要。

    看见 Immutable Update Pattern -这是一个Redux文档,但真正解释了为什么使用可变更新是React的关键。

    function buttonHandler(e) {
      e.preventDefault();
    
      setChartData(chartData => {
        const newChartData = {
          ...chartData,  // <-- shallow copy previous state
          labels: quoteData.map(
            entry => new Date(entry.timestamp).toLocaleTimeString()
          ),
          datasets: chartData.datasets.slice(),  // <-- new datasets array
        };
    
        newChartData.datasets[0] = {
          ...newChartData.datasets[0],                   // <-- shallow copy
          data: quoteData.map(entry => entry['3']),      // <-- then update
        };
        newChartData.datasets[1] = {
          ...newChartData.datasets[1],                   // <-- shallow copy
          data: quoteData.map(({ fastEma }) => fastEma), // <-- then update
        };
        newChartData.datasets[2] = {
          newChartData.datasets[2],                      // <-- shallow copy
          data: quoteData.map(({ slowEma }) => slowEma), // <-- then update
        };
    
        return newChartData;
      });
    }
    

    用电脑检查你的工作 useEffect 钩子依赖于 图表数据 声明:

    useEffect(() => {
      console.log({ chartData });
    }, [chartData]);
    

    如果仍然存在更新问题,请检查 Line 组件,以查看它是否正在对已通过的 data 道具