reactjs - 如果传递变量而不是显式文本,React setState 钩子(Hook)不会更新依赖元素

标签 reactjs react-hooks use-state

我正处于折腾 React 和只使用 vanilla 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>

当我运行上面的命令时,console.log 的输出与它应该的完全一样,但元素没有更新。如果我从控制台复制对象输出并将其显式粘贴到代码中,它就可以工作。

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

我已经尝试了以下语句的所有可以想象的变体,但都无济于事......

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

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

编辑: 作为另一个测试,我添加了以下 HTML 元素以查看它是否已更新。它得到更新并显示预期数据。尽管如此,我还是很难理解为什么图表会在我向它传递显式文本时更新,但如果我向它传递一个变量则不会。

<p>{`${new Date().toLocaleTimeString()} {JSON.stringify(chartData)}`</p>

最佳答案

问题是状态突变。即使您对 chartData 状态进行了浅层复制,您也应该记住这是一个引用副本。每个属性仍然是对原始 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;
  });
}

使用依赖于 chartData 状态的 useEffect Hook 检查您的工作:

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

如果仍然存在更新问题,请检查 Line 组件的代码,看看它是否正在对传递的 data prop 进行任何类型的安装内存。

关于reactjs - 如果传递变量而不是显式文本,React setState 钩子(Hook)不会更新依赖元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71889514/

相关文章:

javascript - 无法让 redux 工具包与异步一起使用(createAsyncThunk)

javascript - 确定在 react 中选中的复选框的方法(useState)

javascript - 在 React 中呈现比以前呈现错误更多的钩子(Hook)

reactjs - React 原生 setInterval useState

javascript - 如何制作单击按钮时显示的加载动画?它应该占据全屏并且应该从右到左并消失

reactjs - 如何在 apollo 客户端中更新查询?

reactjs - 无法让 `lodash.debounce()` 正常工作?多次执行......( react ,lodash,钩子(Hook))

reactjs - 类型错误 : destroy is not a function in Reactjs while call api async function in useEffect hook

reactjs - 错误 : Too many re-renders. React 限制渲染次数以防止无限循环。 react js

reactjs - React Hook 并获取 : How to update a table based on a user input from an API search