首页 > 解决方案 > 当 react 执行 componentDidMount 和 componentWillUnmount

问题描述

我用 React 玩了几年,在某些情况下仍然对挂载/卸载机制感到困惑。

由于挂载/卸载是执行副作用的地方,我不希望它们被随机调用。所以我需要弄清楚它们是如何工作的。据我目前所知,当虚拟dom不存在于真实dom中时,它往往会被卸载。然而,这似乎不是故事的全部,我无法推理

function TestMount(props) {
  useEffect(() => {
    console.log("componentDidMount", props.name);
    return () => {
      console.log("componentWillUnount", props.name);
    };
  }, []);
  return <h1>Test content {" " + JSON.stringify(props.name)}</h1>;
}

function Update({ click }) {
  return <button onClick={click}>Update</button>;
}

function App() {
  const [count, setCount] = useState(0);
  const Component = name => <TestMount name={name} />;
  return (
    <div className="App">
      <h1>{count}</h1>
      <Component name="one" />
      {Component("two")}
      <Update click={() => setCount(x => x + 1)} />
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

组件一是 remount 超时应用程序渲染而组件二不是?为什么会发生这种情况?

标签: reactjs

解决方案


Component每次App渲染都是一个新功能,所以<Component name="one" />每次都重新安装,它们被认为是不同的组件。

Component("two")call的结果是<TestMount name={"two"} />,TestMount每次App渲染都保持不变,所以不会重新挂载。

Component对于它的用途来说是无效的组件,将name字符串作为nameprop 传递给TestMount组件,因为name参数不是字符串,而是 props 对象,当Component使用<Component name="one" />. name => <TestMount name={name} />render function,为了清楚起见,最好将其命名为 like renderTestMount,因为不应该直接调用组件 like Component("two")

如果一个函数应该作为组件或渲染函数互换使用,则签名应更改为({ name }) => <TestMount name={name} />.

<Component name="one" />通过 memoizing可以实现预期的行为Component

const Component = useCallback(({ name }) => <TestMount name={name} />, []);

但由于Component不依赖于App范围,正确的方法是在外部定义它:

const Component = ({ name }) => <TestMount name={name} />;

function App() {...}

例如,这就是 React Router为组件和渲染函数Route单独设置componentrenderprops的原因。这允许防止对需要在当前范围内动态定义的路由组件进行不必要的重新安装。


推荐阅读