React setState触发异常求助:Azure DevOps扩展组件场景
React setState()不更新状态的解决办法
问题场景
在Azure DevOps扩展的Panel组件中,点击按钮后本应先更新IsUserAddedOrUpdated状态以显示加载Spinner,再执行异步函数addOrUpdate(),但实际状态未发生变化,仅addOrUpdate()正常执行。移除addOrUpdate()调用后,setState能正常生效;将setState移至addOrUpdate()内部也无效果。
原问题代码
public render(): JSX.Element { return ( <Panel onDismiss={this.props.onClose} footerButtonProps={[ { text: "Cancel", onClick: this.props.onClose }, { text: this.props.user ? "Save" : "Invite new users", primary: true, onClick: () => { this.setState({ IsUserAddedOrUpdated: true }), this.addOrUpdate(); }, disabled: this.state.inviteButtonDisabled } ]} > <div className="width-100 flex-column"> <ConditionalChildren renderChildren={this.state.IsUserAddedOrUpdated}> <div className="loader"> <Spinner label="Loading..." size={SpinnerSize.large} ></Spinner> </div> </ConditionalChildren> </div> </Panel> ); }
移除addOrUpdate()后的有效代码:
onClick: () => { this.setState({ IsUserAddedOrUpdated: true }) },
问题根因
- React的
setState()是异步批量更新操作,在setState后同步调用addOrUpdate()时,状态尚未完成更新,后续逻辑可能干扰状态的渲染流程; - 若
addOrUpdate()内部存在重置IsUserAddedOrUpdated为false的操作,或触发了组件重新渲染覆盖了之前的状态变更,也会导致Spinner无法正常显示。
解决方法
方法1:利用setState的回调函数
将addOrUpdate()放在setState的第二个参数(回调函数)中,确保状态更新完成后再执行异步逻辑:
onClick: () => { this.setState({ IsUserAddedOrUpdated: true }, () => { this.addOrUpdate(); }); }
方法2:封装setState为Promise配合async/await
自行封装setState为Promise,通过async/await确保状态更新完毕后再执行后续逻辑:
// 封装setState为Promise private setStateAsync = (state: Partial<YourComponentState>) => { return new Promise<void>(resolve => { this.setState(state, resolve); }); }; // 点击事件处理 onClick: async () => { await this.setStateAsync({ IsUserAddedOrUpdated: true }); await this.addOrUpdate(); }
方法3:检查addOrUpdate内部逻辑
排查addOrUpdate()中是否存在请求完成后直接将IsUserAddedOrUpdated设回false的代码,或其他修改状态的逻辑导致状态冲突。比如异步请求刚发起就重置状态,会直接导致Spinner无法显示。
内容的提问来源于stack exchange,提问作者Ali Hasan
相关产品推荐
相关产品推荐

