javascript - 当我从子进程调用它时,useState 值会发生变化

标签 javascript reactjs react-hooks

我正在创建一个使用react-hooks和一系列计时器构建的计时器应用程序 我不明白为什么timerList会改变

这是父组件

const [timerList, setTimerList] = useState([]);


const removeTimer = () => {
  console.log("timerList", timerList);
};

return (
    <div id="main">
      {timerList ? timerList.map((child) => child) : null}
      <div className="add-button before">
        <button
          onClick={() => {
            const time = new Date();
            time.setSeconds(time.getSeconds() + 0);
            setTimerList((timerList) => [
              ...timerList,
              <FullTimer
                expiryTimestamp={time}
                removeTimer={() => {
                  removeTimer();
                }}
                id={window.prompt("Insert timer name") + ` ${timerList.length}`}
                key={timerList.length}
              />,
            ]);
          }}
        >

感兴趣的 child 的组成部分:

<button
  onClick={() => {
     removeTimer();
  }}
>

子组件是一个带有一些CSS的自定义计时器,当我调用removeTimer时,timerList(在父组件中)的值会发生变化,而它应该保持不变。

我错过了什么?

附注按钮标签没有关闭,因为我里面有一些使用 Awesome-font 的元素

最佳答案

旁注:一般来说,将组件存储在另一个组件状态中被认为是不好的做法。


但这并不是真正的问题。给定您的代码,它是 simple closure problem .

这个:

const removeTimer = () => {
  console.log("timerList", timerList);
};

定义关闭当前timerList。因此它会记录它,就像分配removeTimer时一样。目前,每个渲染都会出现这种情况。因此它会记录看似落后一步的状态。这个问题没有解决办法,因为闭包就是这样工作的。

如果您确实想要删除计时器,则在调用 removeTimer 时,您需要使用更新程序的回调版本 (setTimerList) 并传递一些标识值这样您就可以真正删除正确的一个。

如果您遵循最初的建议并且不将组件存储在状态中,而是定义属性,那么这一切都会简单得多。


以下是一个工作示例(请原谅我的 typescript ):

import React, { useState } from 'react';

type FullTimerProps = {
  id: string;
  expiryTimestamp: Date;
  removeTimer: () => void;
}

const FullTimer = ({expiryTimestamp, removeTimer, id}: FullTimerProps): JSX.Element => {
  return (
    <div>
      <button onClick={removeTimer}>remove</button>
      {id}: {expiryTimestamp.toLocaleDateString()}
    </div>
  );
};

type Timer = {
  id: string;
  expiryTimestamp: Date;
};

const TimerList = (): JSX.Element => {
  const [timerList, setTimerList] = useState<Timer[]>([]);

  const removeTimer = (timer: Timer) => {
    setTimerList(timerList => timerList.filter(t => t.id !== timer.id));
  };

  return (
    <div id="main">
      {timerList.map(timer => (
        <FullTimer
          key={timer.id}
          id={timer.id}
          expiryTimestamp={timer.expiryTimestamp}
          removeTimer={() => removeTimer(timer)}
        />
      ))}

      <div className="add-button before">
        <button
          onClick={() =>
            setTimerList(timerList => [...timerList, {
              id: window.prompt('Insert timer name') + ` ${timerList.length}`,
              expiryTimestamp: new Date()
            }])}
        >Add
        </button>
      </div>
    </div>
  );
};

关于javascript - 当我从子进程调用它时,useState 值会发生变化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68748985/

相关文章:

javascript - while 循环中的 setTimeout() 方法

javascript - 使用 jQuery 为 18 岁以上的人验证日期

javascript - 如何在 ReactJS 的同一个类中调用方法?

javascript - react useReducer : How to combine multiple reducers?

javascript - reactStringReplace() 不一致的正则表达式匹配

javascript - 使用钩子(Hook)在 React 组件的多次调用之间共享可变状态

reactjs - 我试图了解 react useEffect Hook

javascript - 使用 HTML 5 Canvas 矩形(像素大小)绘图会得到黑色矩形而不是蓝色?

javascript - 使用 phonegap 和 android 的 javascript 警报中的特殊字符

javascript - 如何使用 react 钩子(Hook)重新渲染组件