React:子组件中的陈旧道具

React: stale props in child component

这是 CodeSandBox link:https://codesandbox.io/s/stale-prop-one-g92sv?file=/src/App.js

我发现点击两次按钮后子组件不会显示正确的计数器值,尽管计数器实际上是递增的:

import "./styles.css";
import { useState } from "react";

const MyComponent = ({ value }) => {
  const [counter] = useState(value);
  return <span>{counter}</span>;
};

export default function App() {
  const [counter, setCounter] = useState(0);
  const isVisible = counter !== 1;
  console.log(counter);
  return (
    <div className="App">
      <div>
        <button onClick={() => setCounter((counter) => counter + 1)}>
          Click me
        </button>
      </div>
      {isVisible && (
        <div>
          Message 1 is: <MyComponent value={counter} />
        </div>
      )}
      <div style={isVisible ? { display: "block" } : { display: "none" }}>
        Message 2 is: <MyComponent value={counter} />
      </div>
    </div>
  );
}

我尝试通过为它的键分配计数器来强制子组件重新渲染:

export default function App() {
  const [counter, setCounter] = useState(0);
  const isVisible = counter !== 1;
  console.log(counter);
  return (
    <div className="App">
      <div>
        <button onClick={() => setCounter((counter) => counter + 1)}>
          Click me
        </button>
      </div>
      {isVisible && (
        <div>
          Message 1 is: <MyComponent  key = {counter} value={counter} />
        </div>
      )}
      <div style={isVisible ? { display: "block" } : { display: "none" }}>
        Message 2 is: <MyComponent key = {counter} value={counter} />
      </div>
    </div>
  );
}

有效,但我仍然不知道为什么以前的无效,因为 MyComponent 中的 props.value 已更改... 提前致谢。

有了这个:

const MyComponent = ({ value }) => {
  const [counter] = useState(value);
  return <span>{counter}</span>;
};

你告诉 React 将初始状态设置为传递给组件的第一个 value 道具,挂载时。

当组件重新渲染时,组件已经被安装,所以传递给 useState 的值被忽略 - 相反,该子项中的 counter 取自 MyComponent 的状态 - 等于 MyComponent 中的初始状态,初始 value 道具已通过。

对于你想要做的事情,你在整个应用程序中只有一个值,你想在任何地方使用它,所以你应该只在父级中有一个 useState 调用 - 然后从 prop 渲染子项中的计数器,它会随着父级状态而改变。

const MyComponent = ({ value }) => {
  return <span>{value}</span>;
};