我在整个应用程序的多个组件中使用以下模式。我注意到许多人不鼓励使用 forceUpdate(),有些人甚至称其为 hack。那么如何在不使用它的情况下完成呢?
// user.js
export default class User extends EventEmitter {
constructor(args) {
super();
this.id = args.id;
this.isActivated = args.isActivated || false;
}
activate() {
this.isActivated = true;
this.emit('change');
}
}
// UserView.jsx
export default class UserView extends React.Component {
componentDidMount() {
this.props.user.on('change', this.onUserUpdate);
}
onUserUpdate() {
this.forceUpdate();
}
render (
var user = this.props.user;
return (
<div>
<span>User {user.isActivated ? 'is' : 'is not'} activated.</span>
<button onClick={user.activate()}>Activate</button>
</div>
);
);
}
// app.js
var user = new User({ id: 123 });
ReactDOM.render(<UserView user={user} />, container);
最佳答案
React 会在 props 或 state 发生变化时自动渲染组件。
如果您有一个属性不断变化的模型,那么您应该将其保持在组件的本地状态。
componentWillMount() {
this.setState({
user: this.props.user
});
}
activator(user) {
return () => {
// mutate the user instance
user.activate();
// update the state to trigger render
this.setState({ user });
};
}
render (
var user = this.state.user;
return (
<div>
<span>User {user.isActivated ? 'is' : 'is not'} activated.</span>
<button onClick={activator(user)}>Activate</button>
</div>
);
)
即使这有点 hacky 并且在状态中存储不可序列化的数据(原型(prototype)关系、函数)也不是很好。我们还在对象处于状态时改变它(哎呀!)。
解决这个问题的(可以说)更优雅的方法是使用一个没有任何实例方法的简单对象来表示用户。然后编写一组纯操作函数,返回反射(reflect)变化的新用户对象。
// user factory
function User(args) {
return {
id: args.id,
isActivated: args.isActivated || false
};
}
function activate(user) {
// returns a new copy with the isActivated property set to true
return Object.assign({}, user, { isActivated: true });
// or with ES2016 object spread
return { ...user, isActivated: true };
}
我们可以将这些用户对象视为不可变的(freeze 如果你愿意的话)。然后您可以修改激活器代码以使其更具功能性。
activator(user) {
return () => {
this.setState({ user: activate(user) });
}
}
现在,当您单击激活按钮时,我们会使用新对象更新组件的状态,而旧对象可以自由地进行垃圾回收。
关于javascript - 如果不鼓励使用 forceUpdate(),组件应该如何对模型中的更改事件使用react?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35617580/