首页 > 解决方案 > 如果单个挂钩状态发生更改,自定义挂钩返回组件会重新呈现所有子组件

问题描述

为什么使用自定义钩子渲染组件会重新渲染 App 组件。如果我切换<Comp> or <AnotherComp>整个 App 组件,则其他组件的重新渲染相同。

我尝试了 React.memo 并将组件再次包装在 App 组件中,但没有效果。

我读到它的反应方式比较和处理函数在渲染之间是不同的。但是有没有人们为此目的使用的高级模式?

export const useCard = (params)=>{
const { ToBeWrappedComponent } = params;
const [isOpen,setIsOpen] = useState(true);

const toggle= ()=> setIsOpen(!isOpen);

const WrappedComponent = ()=>{ 
return (
<Collapse isOpen={isOpen} >
<button onClick= {toggle}> </button>
<ToBeWrappedComponent />
</Collapse>
)
}

return [WrappedComponent,toggle]
};



const App = ()=>{
const [Comp, toggleComp] = useCard({ToBeWrappedComponent: ()=> (<h1>Wrapped Item <h1>) });
const [AnotherComp, toggleAnotherComp] = useCard({ToBeWrappedComponent: ()=> (<h1>Another Wrapped Item <h1>) })

return (
<AnotherComp > </AnotherComp>
<Comp> </Comp>
)
}

请注意,此代码只是我创建的一个示例,用于演示我所面临的情况,我用这个方法做了更复杂的事情,只是想了解实现它的高级模式以及渲染的原因。谢谢

标签: reactjsreact-nativereact-hooks

解决方案


因为这个调用useState实际上是在 App 组件的函数中调用的:

const [isOpen,setIsOpen] = useState(true);

所以它成为App's state 的一部分,而不是被包装组件的 state。

组件会重新渲染,因为每次重新渲染 App 时,WrappedComponent都会重新创建函数。它是一个不同的函数,在内存中具有不同的地址,因此组件树是从头开始重新渲染的。

这是您正在使用的一种非常奇怪的模式。你真的把事情复杂化了。为什么不简单地将渲染函数传递给包装器组件呢?

const TogglableComponent = ({ renderWrappedComponent, isOpen, onClick }) => { 
  return (
    <Collapse isOpen={isOpen} >
      <button onClick={onClick} />
      { renderWrappedComponent() }
    </Collapse>
  )
};

然后,您可以通过 props 从其父组件控制每个组件的切换状态。或者,如果您不关心将切换状态传递给父组件,只需将其存储在包装器中:

const TogglableComponent = ({ renderWrappedComponent }) => {
  const [isOpen, setIsOpen] = React.useState(false);
  return (
    <Collapse isOpen={isOpen} >
      <button onClick={() => setIsOpen(!isOpen)} />
      { renderWrappedComponent() }
    </Collapse>
  )
};

推荐阅读