编辑:查看git存储库以获取最佳示例: https://github.com/maximilianschmitt/blind-lifecycle
我有一个组件RequireUser
,它会尝试确保用户已登录,否则将无法呈现其子级。其父组件App
应该知道是否需要用户并在需要时呈现登录表单。
问题是,App
组件安装在树中的RequireUser
组件之后,如下所示:
App
RequireUser
SomeOtherComponent
在RequireUser
的{{1}}我触发了一项操作componentDidMount
,将requireLogin
的{{1}}变量设置为UserStore
。< / p>
这不会更新父组件(loginRequired
),因为它尚未安装,因此无法将更改注册到商店。
true
输出:
需要用户吗?假
我已经要求您的用户
如果我在App
中使用class RequireUser extends React.Component {
constructor() {
super();
this.state = alt.stores.UserStore.getState();
}
componentDidMount() {
this.unlisten = alt.stores.UserStore.listen(this.setState.bind(this));
if (!this.state.requireUser) {
UserActions.requireUser();
// using setTimeout will work:
// setTimeout(() => UserActions.requireUser());
}
}
componentWillUnmount() {
this.unlisten();
}
render() {
if (this.state.requireUser) {
return <div>I have required your user</div>;
}
return <div>I will require your user</div>;
}
}
class App extends React.Component {
constructor() {
super();
this.state = alt.stores.UserStore.getState();
}
componentDidMount() {
this.unlisten = alt.stores.UserStore.listen(this.setState.bind(this));
}
componentWillUnmount() {
this.unlisten();
}
render() {
return (
<div>
<div>User required? {this.state.requireUser + ''}</div>
<RequireUser />
</div>
);
}
}
,则setTimeout
会收到状态更改并呈现,但仅在闪烁之后:
需要用户吗?真
我已经要求您的用户
我感觉我正在做的是一个反模式,我会感谢更优雅的解决方案的建议,而不是使用setTimeout闪烁。谢谢!
答案 0 :(得分:1)
我建议的答案是将其添加到App组件:
componentDidMount() {
// setup listener for subsequent changes
alt.stores.UserStore.listen(this.onChange);
// grab the current state now that we're mounted
var userStoreState = alt.stores.UserStore.getState();
this.setState(userStoreState);
}
无法避免双重渲染。您的RequireUser组件已执行两次渲染。
但您的代码库仍被视为Flux,并且确实遵循React应用程序的模式。从本质上讲,你有一个加载状态......一个我们实际上不知道是否需要用户的状态。根据 UserActions.requireUser()的作用,这可能是也可能不需要。
您可以考虑使用重构
如果您将RequireUser重写为仅查看组件,则可以修复双重渲染。这意味着没有监听器也没有内部设置状态。这个组件只是根据传入的props渲染元素。这就是你的所有RequireUser组件都是:
class RequireUser extends React.Component {
render() {
if (this.props.requireUser) {
return <div>I have required your user</div>;
}
return <div>I will require your user</div>;
}
}
然后,您将使您的应用程序组件成为 controller-view 。这里添加了监听器,对状态的任何更改都通过props向下传播。现在我们可以在componentWillMount回调中进行设置。这为我们提供了单一的渲染行为。
class App extends React.Component {
(other lifecycle methods)
componentWillMount() {
if (!this.state.requireUser) {
UserActions.requireUser();
}
var userStoreState = alt.stores.UserStore.getState();
this.setState(userStoreState);
}
componentDidMount() {
(same as above)
}
render() {
return (
<div>
<div>User required? {this.state.requireUser + ''}</div>
<RequireUser requireUser={this.state.requireUser} />
</div>
);
}
}
Flux架构和控制器视图/视图:https://facebook.github.io/flux/docs/overview.html#views-and-controller-views
答案 1 :(得分:1)
只有在构建每个组件时,您的组件才会从您的商店一次获取states
。这意味着您的组件中的states
将不与states
store
同步
您需要在安装时在组件上设置store
侦听器,以便从store
和最新states
中检索触发器。使用setState()
更新组件内的states
,以便再次调用render()
以呈现最新的states