如何从 `componentDidUpdate` 中调用 `dispatch` 而不会陷入无限循环?
How can I call `dispatch` from within `componentDidUpdate` without ending up in a infinite loop?
我正在制作一个非常简单的 React 组件,它显示从远程源获取的数据。在获取数据之前,它必须等待用户正确登录。这是我尝试执行此操作的方法:
class MyComponent extends React.Component {
componentDidUpdate () {
if (this.props.loggedIn) {
api.getData()
.then(() => {
this.props.dispatch({
type: 'gotData'
})
}, (reason) => {
this.props.dispatch({
type: 'getDataFailed'
})
})
}
}
}
用我自己的话说,每次与这个组件相关的状态的一部分(在本例中,loggedIn
prop)被更新,componentDidUpdate
被调用,我可以得到数据如果我看到用户已登录。
这实际上工作得很好,除了一个主要问题:似乎调用 dispatch
最终会再次触发 componentDidUpdate
,所以我陷入了无限循环。我什至不必在任何地方监听这些调度事件,使用 dispatch
函数的简单事实足以再次触发 componentDidUpdate
。
我的猜测是 dispatch 执行了我内部使用 setState
的 root reducer,从而再次触发了整个 update
生命周期链。
这种事情一般是怎么做的?如何从 componentDidUpdate
中调用 dispatch
而不会陷入无限循环?
解决这个问题的一个简单方法是添加一个额外的标志,例如 loggingIn
,您在异步操作之前设置(通过调度)并在之后重置。您还需要跟踪登录失败的时间,以区分这种情况与登录过程未启动的时间(除非您想在失败时自动重新启动该过程):
class MyComponent extends React.Component {
componentDidUpdate () {
const { loggedIn, loggingIn, loginFailed, dispatch } = this.props;
if (!loggingIn && !loggedIn && ! loginFailed) {
dispatch({
type: 'gettingData' // this one sets loggingIn to true, loggedIn to false, loginFailed to false
});
api.getData()
.then(() => {
dispatch({
type: 'gotData' // this one sets loggingIn to false, loggedIn to true, loginFailed to false
})
}, (reason) => {
dispatch({
type: 'getDataFailed' // this one sets loggingIn to false, loggedIn to false, loginFailed to true
})
})
}
}
}
如果你不想在 redux 中设置这个状态,你也可以让这个控件存在于你的组件中:
class MyComponent extends React.Component {
componentDidUpdate () {
const { loggedIn, dispatch } = this.props;
const { loggingIn, loginFailed } = this.state;
if (!loggingIn && !loggedIn && !loginFailed) {
this.setState({
loggingIn: true
})
api.getData()
.then(() => {
this.setState({
loggingIn: false,
loginFailed: false
});
dispatch({
type: 'gotData'
})
}, (reason) => {
this.setState({
loggingIn: false,
loginFailed: true
});
dispatch({
type: 'getDataFailed'
})
})
}
}
}
您可以使用 loggingIn
标志向您的用户显示微调框,或者使用 loginFailed
标志显示一条消息,如果这适合您的用户体验。
当您收到登录状态后,请将您的 api 号召性用语移至号召性用语!像这样:
api.getUserLoggedInStatus().then((status) => {
dispatch({
type: 'loggedInStatus',
status
});
api.getData.... // and dispatch
};
此流程将避免任何循环或竞争条件。
我正在制作一个非常简单的 React 组件,它显示从远程源获取的数据。在获取数据之前,它必须等待用户正确登录。这是我尝试执行此操作的方法:
class MyComponent extends React.Component {
componentDidUpdate () {
if (this.props.loggedIn) {
api.getData()
.then(() => {
this.props.dispatch({
type: 'gotData'
})
}, (reason) => {
this.props.dispatch({
type: 'getDataFailed'
})
})
}
}
}
用我自己的话说,每次与这个组件相关的状态的一部分(在本例中,loggedIn
prop)被更新,componentDidUpdate
被调用,我可以得到数据如果我看到用户已登录。
这实际上工作得很好,除了一个主要问题:似乎调用 dispatch
最终会再次触发 componentDidUpdate
,所以我陷入了无限循环。我什至不必在任何地方监听这些调度事件,使用 dispatch
函数的简单事实足以再次触发 componentDidUpdate
。
我的猜测是 dispatch 执行了我内部使用 setState
的 root reducer,从而再次触发了整个 update
生命周期链。
这种事情一般是怎么做的?如何从 componentDidUpdate
中调用 dispatch
而不会陷入无限循环?
解决这个问题的一个简单方法是添加一个额外的标志,例如 loggingIn
,您在异步操作之前设置(通过调度)并在之后重置。您还需要跟踪登录失败的时间,以区分这种情况与登录过程未启动的时间(除非您想在失败时自动重新启动该过程):
class MyComponent extends React.Component {
componentDidUpdate () {
const { loggedIn, loggingIn, loginFailed, dispatch } = this.props;
if (!loggingIn && !loggedIn && ! loginFailed) {
dispatch({
type: 'gettingData' // this one sets loggingIn to true, loggedIn to false, loginFailed to false
});
api.getData()
.then(() => {
dispatch({
type: 'gotData' // this one sets loggingIn to false, loggedIn to true, loginFailed to false
})
}, (reason) => {
dispatch({
type: 'getDataFailed' // this one sets loggingIn to false, loggedIn to false, loginFailed to true
})
})
}
}
}
如果你不想在 redux 中设置这个状态,你也可以让这个控件存在于你的组件中:
class MyComponent extends React.Component {
componentDidUpdate () {
const { loggedIn, dispatch } = this.props;
const { loggingIn, loginFailed } = this.state;
if (!loggingIn && !loggedIn && !loginFailed) {
this.setState({
loggingIn: true
})
api.getData()
.then(() => {
this.setState({
loggingIn: false,
loginFailed: false
});
dispatch({
type: 'gotData'
})
}, (reason) => {
this.setState({
loggingIn: false,
loginFailed: true
});
dispatch({
type: 'getDataFailed'
})
})
}
}
}
您可以使用 loggingIn
标志向您的用户显示微调框,或者使用 loginFailed
标志显示一条消息,如果这适合您的用户体验。
当您收到登录状态后,请将您的 api 号召性用语移至号召性用语!像这样:
api.getUserLoggedInStatus().then((status) => {
dispatch({
type: 'loggedInStatus',
status
});
api.getData.... // and dispatch
};
此流程将避免任何循环或竞争条件。