在单击按钮时反应添加和删除组件

React add and remove a component on button click

我是 React 新手。在这里,我试图在单击 +/- 按钮时 add/remove 一个 'Timer' 组件。单击“+”时效果很好,但单击“-”时效果不佳。我认为每次设置状态时,组件都会重新呈现。但是这里它不会在单击“-”按钮时呈现。

  1. 这里可能出了什么问题?
  2. 也欢迎任何更好的方法来做同样的事情。
function App() {
  var [timers, setTimers] = useState([]);
  var [count, setCount] = useState(0);

  const addTimer = () => {
    setCount(count + 1);
    timers.push(count);
    setTimers(timers);
    console.log(timers); //[0]
  };

  const removeTimer = () => {
    timers.pop();
    setTimers(timers);
    console.log(timers); //[]
  };

  return (
    <div>
      <button className="button" onClick={addTimer}>
        +
      </button>

      <button className="button" onClick={removeTimer}>
        -
      </button>

      <div>
        {timers.map((t) => (
          <Timer key={t} />
        ))}
      </div>
    </div>
  );
}

问题在于,只有在状态发生变化时,React 才会重新渲染。它通过进行 浅比较来检查该事实。 因此,对于对象(或数组,如您的情况),即使您正在更改对象的内容,对象 reference 保持不变。因为 timers.pop() 不会创建新数组。它修改当前数组。

React 会做类似的事情:old array === new array ? 并且会返回 true,因为它是相同的 array/object 引用。

PS:您的 (+) 按钮之所以起作用,是因为您也在做 setCount(count+1)。顺便说一下,您应该将其更改为 setCount((prevState) => prevState + 1);

当您的新状态取决于您的上一个状态时,我建议您始终使用这种形式的 setState 调用:

setState((prevState) => {
  // READ AND USE OLD prevState
  // RETURN BRAND NEW newState
});

你可以这样做:

const addTimer = () => {
  setCount((prevState) => prevState + 1);
  setTimers((prevState) => {
    const newTimers = Array.from(prevState);  // CREATING A NEW ARRAY OBJECT
    timers.push(count);
    return newTimers;  
  });
};

const removeTimer = () => {
  setTimers((prevState) => {
    const newTimers = Array.from(prevState);  // CREATING A NEW ARRAY OBJECT
    newTimers.pop();
    return newTimers;  
  });
};

您正在改变不会触发渲染的状态,请参阅 React 文档中的 Power Of Not Mutating Data

重写为不可变逻辑可以是:

const addTimer = () => {
  setCount((prevCount ) => prevCount + 1);
  setTimers((prevTimers) => [...prevTimers, count]);
};

const removeTimer = () => {
  setTimers((prevTimers) => prevTimers.slice(0, prevTimers.length - 1));
};

因为您正试图改变状态。这里(在 React 中)有一个不改变状态的原则。所以你不应该 pop 而是在 remove 函数中做类似的事情。它可以帮助您避免任何副作用:

setTimers(state => state.filter((timer, index) => index !== state.length - 1))

测试 React sandbox

它不起作用的原因可能是您 add/remove 使用 push/pop 方法的错误方式。

如果您希望组件重新呈现,则需要使用解构来更改状态。

可能不是最佳解决方案,但应该可行:

const addTimer = () => {
    setCount(count + 1)
    setTimers([...timers, count])
}

const removeTimer = () => {
    let filteredTimers = timers.filter((timer, index) => index !== (timers.length-1))
    setTimers([...filteredTimers])
}