reactjs - 如果单个挂钩状态发生更改,自定义挂钩返回组件会重新呈现所有子组件
问题描述
为什么使用自定义钩子渲染组件会重新渲染 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>
)
}
请注意,此代码只是我创建的一个示例,用于演示我所面临的情况,我用这个方法做了更复杂的事情,只是想了解实现它的高级模式以及渲染的原因。谢谢
解决方案
因为这个调用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>
)
};
推荐阅读
- elasticsearch - 如何使用 json 过滤器将我的 json 日志文件存储到 logstash
- sql - SQLite 更新行
- ios - UICollectionView 将在调用“reloadItems”方法时重新创建单元格
- html - 如何使表单字段响应?
- java - OpenCV Java [WARN:2] videoio(MSMF):无法抓取帧。错误:-1072875772
- python-3.x - 如何使用 for 循环在决策树上正确实现 bagging?
- c# - 在自动滚动表单c#中绘制线条
- javascript - 通过多个属性下划线对数组中的元素进行分组
- mysql - SQL获取行等于某事的最大列数
- php - Laravel 从不同的 ID 获取所有行