代码:
根成分
<Provider store={Store}>
<AppLayoutContainer>
{this.props.template}
</AppLayoutContainer>
</Provider>
应用程序布局容器
....some code
return(
<div className={`AppLayoutContainer`}>
<Modal isOpen={isModalShown} .... />
<div>{children}</div>
</div>
)
....some code
function mapStateToProps(state) {
const { app } = state;
return {
isModalShown: app.isModalShown
}
}
export default connect(mapStateToProps)(AppLayoutContainer);
问题:
每次Applayoutcontainer从Redux获得isModalShown
时,我的整个应用程序都在重新渲染,这非常糟糕。我只需要重新渲染Modal组件,不要触摸我的children
。我认为ShouldComponentUpdate
方法是可能的,但我真的不知道怎么做
有什么想法吗?我知道有人在他的项目中做到了这一点,并可以为此提供一些最佳实践建议。感谢
更新:
阅读所有答案,是的,将Modal与Store连接是一个很好的解决方案,但是如果
1( 我希望Modal组件是纯的(可重复使用(,像还是组件?
2( 我需要在AppLayoutContainer中使用isModalShown
吗?
return(
<div className={`AppLayoutContainer`}>
<Modal isOpen={isModalShown} .... />
<div>{children}</div>
</div>
)
更新2.0
谢谢你的回答,但我能用这个做什么
主要的问题是,当我显示Modal
组件时,我需要模糊我的所有内容,因为我知道blur()
只能应用于要工作的内容(而不是覆盖我的内容的绝对位置div(,并且像这个一样
return(
<div className={`AppLayoutContainer`}>
<Modal isOpen={isModalShown} .... />
<div className={isModalShown ? 'blured' : null }>{children}</div>
</div>
)
但每次我显示Modal
时,我的整个应用程序都会重新渲染,我需要冻结它。在这里为child
构建容器并执行shouldcomponentupdate
的解决方案不好,React如何比较whole组件??它只比较道具中不可变的字段。
有什么解决方案吗?
您应该做的不是传递AppLayoutContainer
的mapStateToProps
函数中的isModal
,而是传递connect
Modal
本身。
mapStateToProps
的任何更改结果都将导致connect
ed组件重新发送。在您的情况下,mapStateToProps
connect
到AppLayoutContainer
返回isModalShown
的值,这将导致AppLayoutContainer
重新发送。
如果你只想重新发送Modal
本身,那么只需要
export default connect(state => ({isOpen: state.app.isModalShown}))(Modal)
在你的Modal
文件中,或者如果你更喜欢的话,放在一个单独的文件中。
另外,从AppLayoutContainer
中删除isModalShown
道具,因为您不需要它,因为将其保留在那里意味着每次isModalShown
更改时,AppLayoutContainer
仍将重新发送(这正是您试图修复的(。
更新关于问题更新:
问题1:
你可以有一个纯Modal
export default function Modal(props) {
return <span>Open={props.isOpen}</span>;
}
然后,您可以为特定用途制作特定的模式:
import Modal from './modal';
import { connect } from 'react-redux';
export default const AppLayoutModal = connect(state => ({isOpen: state.app.isModalShown}))(Modal);
你可以对各种不同的模态多次这样做。事实上,这就是为什么使用纯组件是个好主意。
问题2:
如果你想在AppLayoutContainer
中使用isModalShown
,那么你有一些选择:
- 只要使用它。React总是渲染整个组件。因为这只是一种渲染方法。它会更新DOM(如果有的话(,使其更细粒度,但如果您希望在某个东西发生变化时渲染更少的东西,那么就由您来缩小渲染函数。如果你把组件放大,那么整个组件就会重新出现
- 您可以将组件分解为更小的组件,以便分别渲染它们。您可以通过
connect
直接使一个小组件只使用isModalShown
,这样大的AppLayoutContainer
就不会改变。子零部件可以并且确实独立于其父零部件进行更新
更新2
要模糊整个应用程序,只需在应用程序中添加一个类即可。子组件将不会重新应答。Redux阻止子级渲染,因为它注意到子级没有使用isModalShown
。生成的React元素与上一次渲染的对象(引用(完全相同。React看到它是同一个元素,并知道不要更新整个树。这是因为React元素是不可变的。你的整个应用程序不会重新发送。事实上,React只会在class属性中添加或删除class。
如果您的子级不使用Redux来阻止渲染在树上进行,则可以将子级封装在Redux连接的组件中。或者,也可以使用shouldComponentUpdate
来防止渲染子对象。
Bare React要求您从根向树下发送数据。Redux要求您在需要数据的地方将数据注入树中。后者的好处是不需要重新考虑其他因素。如果没有Redux,除了组件使用shouldComponentUpdate
停止传播外,每次更改都会重新绘制整个树。但是,这不仅会停止当前组件的渲染,还会停止所有子组件的渲染。Redux消除了这一点,因为子组件可以在没有父组件合作或知情的情况下更新其道具。
简而言之:在任何地方使用Redux都可以提高速度。
这里可能有不同的策略。
- 在您的子组件中使用
shouldComponentUpdate
(在这种情况下非常混乱和不雅( - 将Modal组件连接到商店,而不是
AppLayoutContainer
- 将
isModalShown
存储在Modal
的状态,而不是全局状态
在可能的情况下,最后的解决方案通常是更合适的IMHO。您将UI状态保留在相关组件中,因为您不需要经常在其他组件中意识到这一点。
class Modal extends Component {
state = {
isModalShown: false,
};
render() {
// ...
}
}
如果您需要在其他地方了解isModalShown
,则应连接Modal
组件,而不是AppLayoutContainer
。
export default connect((state) => ({
isModalShown: state.app.isModalShown,
}))(Modal)
我认为DDS和Anthony Dugois有权这样做,但如果这些不是你想要的答案,你可以总是将children
管道传输到一个新组件中,并在那里使用shouldComponentUpdate
。