在我的React应用程序中,我使用了一些库(即Material UI和React Intl)将React元素作为道具从更高级别的组件传递到具有一个作业的“哑组件”:渲染。
智能组件:
import ActionExplore from 'material-ui/svg-icons/action/explore';
import { FormattedMessage } from 'react-intl';
export class SmartComponent extends Component {
render() {
return (
<div>
<DumbComponent
text={<FormattedMessage id="en.dumbComponent.text" />}
icon={<ActionExplore/>}
/>
<AnotherDumbComponent {props.that.are.changing} />
</div>
);
}
}
哑组件:
import shallowCompare from 'react-addons-shallow-compare';
export class DumbComponent extends Component {
shouldComponentUpdate(nextProps, nextState) {
return shallowCompare(this, nextProps, nextState);
}
render() {
return (
<div>
<h1>{this.props.text}</h1>
{this.props.icon}
</div>
);
}
}
这样做的好处是,DumbComponent不需要了解任何有关应用程序逻辑(材料ui,国际化等)的知识。它只是呈现,让SmartComponent处理所有业务逻辑。
我遇到这种方法的缺点是性能:DumbComponent将总是重新渲染,即使AnotherDumbComponent的道具改变而不是它自己的道具,因为shouldComponentUpdate
总是返回true
。 shouldComponentUpdate
无法在上例中的React元素之间进行准确的等式检查。
如何在shouldComponentUpdate
中对React元素进行相等检查?执行成本太高了吗?将React元素作为道具传递给哑组件是一个坏主意吗?是否有可能将不传递给React元素作为道具,但保持组件愚蠢?谢谢!
答案 0 :(得分:0)
是否具有高性能将取决于您的用例。根据经验,我认为当你期望用户输入只影响“哑组件”的孩子而不是它的同伴时,最好使用这种逻辑。
例如,Material-UI的Dialog与你的动作按钮和标题的建议几乎相同。 (https://github.com/callemall/material-ui/blob/master/src/Dialog/Dialog.js#L292)。但是在这种情况下效果很好,因为这些元素在模态上,除非你打开或关闭它,否则它本身不会修改。
作为另一种潜在的解决方法,如果传入创建子元素所需的对象而不传入整个元素,该怎么办?我没试过这个,所以我不确定它会有多好用,但值得一试。达到某种程度;
<DumbComponent
textComponent={FormattedMessage}
textProps={{id: "en.dumbComponent.text"}}/>
//In DumbComponent;
render(){
return (
<div>
<h1>
<this.props.textComponent {...this.props.textProps}/>
</h1>
</div>
);
}
在确定是否应该更新时,可能会给你一些更具体的事情。
答案 1 :(得分:0)
我通过将这些简单的React元素转换为Immutable.js地图并将它们作为道具传递来解决这个问题。
这篇文章非常有用:https://www.toptal.com/react/react-redux-and-immutablejs
Immutable.js允许我们检测JavaScript对象/数组中的更改,而不会诉诸深度相等检查的低效率,这反过来允许React避免在不需要时进行昂贵的重新呈现操作。