reactjs - 将组件包装在函数、事件处理和状态 Hook 内的组合表现出意外

标签 reactjs

这些因素的组合会导致意外的行为:

  • 从父组件中的函数返回子组件
  • 在子组件内有一个 onClick 监听器,通过钩子(Hook)调用更新它自己的状态
  • 让同一个监听器调用更新父状态的事件监听器

我在codesandbox.io上做了一个例子:https://codesandbox.io/s/nice-kepler-bur5h

const ChildComponent = ({ onClick, title }) => {
  const [isButtonClicked, setIsButtonClicked] = useState(false);
  return (
    <div className="childComponent">
      <h2>{title}</h2>
      <pre>{JSON.stringify({ isButtonClicked }, null, 2)}</pre>
      <button
        onClick={() => {
          setIsButtonClicked(true);
          onClick();
        }}
      >
        button
      </button>
    </div>
  );
};

function App() {
  const [value, setValue] = useState(true);
  const WrappedChildComponent = () => (
    <ChildComponent
      title="wrapped child"
      onClick={() => {
        setValue(!value);
      }}
    />
  );
  return (
    <div className="App">
      <h2>parent</h2>
      <pre>{JSON.stringify({ value }, null, 2)}</pre>
      <button onClick={() => setValue(true)}>reset value</button>
      <div>
        <ChildComponent
          title="child"
          onClick={() => {
            setValue(!value);
          }}
        />
        <WrappedChildComponent />
      </div>
    </div>
  );
}

当单击按钮时,WrappedChildComponent 不会更新自己的 isButtonClicked,而普通的 ChildComponent 会更新。

我希望包装的组件的行为类似于普通的子组件。

什么原因导致这种行为?

最佳答案

要实现此功能,您需要使用 useEffect Hook 来创建 WrappedChildComponent:

function App() {
  const [value, setValue] = useState(true)
  const [wrappedChildComponent, setWrappedChildComponent] = useState(null)

  useEffect(() => {
    setWrappedChildComponent(
      <ChildComponent
        title="wrapped child"
        onClick={() => { setValue(!value) }
      />
    )

  // IMPORTANT: put `value` (since that what it depends on) 
  // in your dependency array so you don't 
  // get an infinite loop (rendering forever)
  }, [value])

  return (
    <div> 
      ...
      <div>
        <ChildComponent
          title="child"
          onClick={() => { setValue(!value); }} 
        />
        {wrappedChildComponent}
      </div>
    </div>
  )

这修复了 WrappedComponent 内部的 isButtonClicked 无法设置其自身状态的问题。按照您的方式,WrappedComponent 本质上是在 App 内部缓存的,因此您需要创建一个额外的 Hook 才能正确处理这种情况。

此外,如果您依赖 WrappedComponent 内部 Appvalue 状态,那么您也会看到奇怪的行为(来自 Appvalue 未在 WrappedComponent 内部更新),至少是您最初的方式。上述解决方案兼顾了两者。

这是演示的链接:

关于reactjs - 将组件包装在函数、事件处理和状态 Hook 内的组合表现出意外,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57443756/

相关文章:

javascript - React .map() 不是函数错误

javascript - React NPM 包可以防止、搜索和监控状态发生突变的地方

reactjs - React Typescript - React 组件类中的上下文

javascript - react 路由器 : Component not getting displayed

reactjs - 如何在React JS中的另一个函数中为一个函数的变量赋值

reactjs - 为什么只有一个 react native 并行动画在运行而另一个没有运行?

reactjs - 开 Jest ,意外的 token 导入

css - 如何在 Webpack 4 中启用 SASS 模块

javascript - Material-ui:如何停止在嵌套组件中传播点击事件

javascript - Heroku - 部署 React/Express 应用程序并在请求 chunk.js 文件时在控制台中获取 'Failed to load resource'