Javascript 反应+;Alt:生命周期缺口
编辑:查看git存储库以获得一个小示例: 我有一个组件Javascript 反应+;Alt:生命周期缺口,javascript,reactjs,flux,alt.js,Javascript,Reactjs,Flux,Alt.js,编辑:查看git存储库以获得一个小示例: 我有一个组件RequireUser,它试图确保用户已登录,否则不会呈现其子项。它的父组件,App,应该知道是否需要用户,并在需要时提供登录表单 问题是,App组件安装在RequireUser组件之后的树中,如下所示: App RequireUser SomeOtherComponent 在RequireUser的componentDidMount中,我触发了一个动作requireLogin,该动作将UserStore的loginRequir
RequireUser
,它试图确保用户已登录,否则不会呈现其子项。它的父组件,App
,应该知道是否需要用户,并在需要时提供登录表单
问题是,App
组件安装在RequireUser
组件之后的树中,如下所示:
App
RequireUser
SomeOtherComponent
在RequireUser
的componentDidMount
中,我触发了一个动作requireLogin
,该动作将UserStore
的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>
);
}
}
类RequireUser扩展了React.Component{
构造函数(){
超级();
this.state=alt.stores.UserStore.getState();
}
componentDidMount(){
this.unlisten=alt.stores.UserStore.listen(this.setState.bind(this));
如果(!this.state.requireUser){
UserActions.requireUser();
//使用setTimeout将起作用:
//setTimeout(()=>UserActions.requireUser());
}
}
组件将卸载(){
这是我的;
}
render(){
if(this.state.requireUser){
返回我已要求您的用户;
}
返回我将要求您的用户;
}
}
类应用程序扩展了React.Component{
构造函数(){
超级();
this.state=alt.stores.UserStore.getState();
}
componentDidMount(){
this.unlisten=alt.stores.UserStore.listen(this.setState.bind(this));
}
组件将卸载(){
这是我的;
}
render(){
返回(
需要用户?{this.state.requireUser+''}
);
}
}
输出:
用户要求?假的
我需要你的用户
如果在RequireUser
中使用setTimeout
,App
接收状态更改并呈现,但仅在闪烁之后:
用户要求?真的
我需要你的用户
我觉得我所做的是一种反模式,如果能提供比使用setTimeout闪烁更优雅的解决方案,我将不胜感激。谢谢 我建议的答案是将其添加到应用程序组件中:
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组件已经执行了两次渲染
- 发出一个动作
- 发出更改通知
<强>您可以考虑重构< <强>
如果将RequireUser重写为仅查看组件,则可以修复双重渲染。这意味着没有监听器,也没有在内部设置状态。该组件只是基于传入的道具渲染元素。这就是您的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>;
}
}
类RequireUser扩展了React.Component{
render(){
如果(此.props.requireUser){
返回我已要求您的用户;
}
返回我将要求您的用户;
}
}
然后,您将使应用程序组件成为控制器视图。监听器添加到这里,对状态的任何更改都会通过道具向下传播。现在我们可以在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>
);
}
}
类应用程序扩展了React.Component{
(其他生命周期方法)
组件willmount(){
如果(!this.state.requireUser){
UserActions.requireUser();
}
var userStoreState=alt.stores.UserStore.getState();
this.setState(userStoreState);
}
componentDidMount(){
(同上)
}
render(){
返回(
需要用户?{this.state.requireUser+''}
);
}
}
Flux体系结构和控制器视图/视图:您的每个组件仅从您的存储获取
状态一次
——仅在构建每个组件期间。这意味着组件中的状态将与存储中的状态不同步
在安装组件时,您需要在组件上设置存储
侦听器,以便从存储
中检索触发器和最新的状态
。使用setState()
更新组件内部的状态
,以便再次调用render()
来呈现最新的状态
将存储侦听器放入构造函数中如何?这对我很有效。多亏了托比,我已经试过了,并决定不使用它,因为埃斯林特建议不要在componentDidMount
中使用setState
。它触发了一个额外的渲染,所以它不是很好,不幸的是,即使它确实工作。还有其他想法吗?看起来componentWillMount()可能真的会起作用。根据docs,如果在此回调期间执行setState(),则这些更新只会执行一次渲染。你觉得怎么样?嘿,托比!不幸的是,在子组件的componentDidMount
之前调用父组件的componentWillMount
。在这里设置一个侦听器可能会起作用,但我对此不太感兴趣,因为这会导致一个备忘录