在 React class 组件中设置动作前后的加载状态
Set loading state before and after an action in a React class component
我有发送动作的函数。我想在操作前后显示一个加载程序。我知道 react 组合传递给 setState
的对象。问题是如何以异步方式更新 属性:
handleChange(input) {
this.setState({ load: true })
this.props.actions.getItemsFromThirtParty(input)
this.setState({ load: false })
}
基本上,如果我将这个 属性 作为应用程序状态的一部分(使用 Redux),一切都很好,但我真的更喜欢只将这个 属性 带到组件状态。
将其余代码包装在第一个 setState
:
的回调中
handleChange(input) {
this.setState({
load: true
}, () => {
this.props.actions.getItemsFromThirtParty(input)
this.setState({ load: false })
})
}
有了这个,您的 load
可以保证在 getItemsFromThirtParty
被调用之前被设置为 true
并且 load
被设置回 false
。
这假设您的 getItemsFromThirtParty
函数是同步的。如果不是,将它变成一个承诺,然后在链式 then()
方法中调用最终的 setState
:
handleChange(input) {
this.setState({
load: true
}, () => {
this.props.actions.getItemsFromThirtParty(input)
.then(() => {
this.setState({ load: false })
})
})
}
您可以执行以下操作...
- 更改您的操作以接收
onFetchComplete
回调以及 input
。
将 handleChange 更改为 -
handleChange(input) {
this.setState({ load: true }, ()=>
this.props.actions.getItemsFromThirtParty(input,
()=>this.setState({ load: false }))
);
}
这将确保动作处理器代码可以调用回您的状态更改回调,即使它不是以基于承诺的方式编写的。
一个小的更新——对动作创建者使用承诺,async/await 效果很好,与 "then" 链接相比,它使代码更加简洁:
(async () => {
try {
await this.props.actions.async1(this.state.data1);
await this.props.actions.async2(this.state.data2)
this.setState({ load: false );
} catch (e) {
this.setState({load: false, notify: "error"});
}
})();
当然是个人喜好问题。
编辑:添加了缺失的括号
您可以将 setState 包装在 Promise 中并使用 async/await,如下所示
setStateAsync(state) {
return new Promise((resolve) => {
this.setState(state, resolve)
});
}
async handleChange(input) {
await this.setStateAsync({ load: true });
this.props.actions.getItemsFromThirtParty(input);
await this.setStateAsync({ load: false })
}
这是 "async-await" setState 的打字稿实现:
async function setStateAsync<P, S, K extends keyof S>(
component: Component<P, S>,
state:
((prevState: Readonly<S>, props: Readonly<P>) => (Pick<S, K> | S | null)) |
Pick<S, K> |
S |
null
) {
return new Promise(resolve => component.setState(state, resolve));
}
前面的答案不适用于 Hooks。在这种情况下,将第二个参数传递给 setState
时会出现以下错误
Warning: State updates from the useState() and useReducer() Hooks don't support the second callback argument. To execute a side effect after rendering, declare it in the component body with useEffect().
如错误消息所述,在这种情况下您需要使用 useEffect
(另请参阅 了解更多详细信息)
我知道这是关于 class 组件的...但是在功能组件中我这样做是为了同步设置状态:
const handleUpdateCountry(newCountry) {
setLoad(() => true);
setCompanyLocation(() => newCountry);
setLoad(() => false);
}
刚刚为我的自动国家/地区检测工作,应该将表单设置为脏。
任何其他答案中都没有提到的一种方法是将操作包装在 setTimeout 中。如果您使用钩子,这也将起作用。
例如:
handleChange(input) {
this.setState({ load: true })
setTimeout(() => {
this.props.actions.getItemsFromThirtParty(input).finally(() => {
this.setState({ load: false })
});
});
}
我有发送动作的函数。我想在操作前后显示一个加载程序。我知道 react 组合传递给 setState
的对象。问题是如何以异步方式更新 属性:
handleChange(input) {
this.setState({ load: true })
this.props.actions.getItemsFromThirtParty(input)
this.setState({ load: false })
}
基本上,如果我将这个 属性 作为应用程序状态的一部分(使用 Redux),一切都很好,但我真的更喜欢只将这个 属性 带到组件状态。
将其余代码包装在第一个 setState
:
handleChange(input) {
this.setState({
load: true
}, () => {
this.props.actions.getItemsFromThirtParty(input)
this.setState({ load: false })
})
}
有了这个,您的 load
可以保证在 getItemsFromThirtParty
被调用之前被设置为 true
并且 load
被设置回 false
。
这假设您的 getItemsFromThirtParty
函数是同步的。如果不是,将它变成一个承诺,然后在链式 then()
方法中调用最终的 setState
:
handleChange(input) {
this.setState({
load: true
}, () => {
this.props.actions.getItemsFromThirtParty(input)
.then(() => {
this.setState({ load: false })
})
})
}
您可以执行以下操作...
- 更改您的操作以接收
onFetchComplete
回调以及input
。 将 handleChange 更改为 -
handleChange(input) { this.setState({ load: true }, ()=> this.props.actions.getItemsFromThirtParty(input, ()=>this.setState({ load: false })) ); }
这将确保动作处理器代码可以调用回您的状态更改回调,即使它不是以基于承诺的方式编写的。
一个小的更新——对动作创建者使用承诺,async/await 效果很好,与 "then" 链接相比,它使代码更加简洁:
(async () => {
try {
await this.props.actions.async1(this.state.data1);
await this.props.actions.async2(this.state.data2)
this.setState({ load: false );
} catch (e) {
this.setState({load: false, notify: "error"});
}
})();
当然是个人喜好问题。
编辑:添加了缺失的括号
您可以将 setState 包装在 Promise 中并使用 async/await,如下所示
setStateAsync(state) {
return new Promise((resolve) => {
this.setState(state, resolve)
});
}
async handleChange(input) {
await this.setStateAsync({ load: true });
this.props.actions.getItemsFromThirtParty(input);
await this.setStateAsync({ load: false })
}
这是 "async-await" setState 的打字稿实现:
async function setStateAsync<P, S, K extends keyof S>(
component: Component<P, S>,
state:
((prevState: Readonly<S>, props: Readonly<P>) => (Pick<S, K> | S | null)) |
Pick<S, K> |
S |
null
) {
return new Promise(resolve => component.setState(state, resolve));
}
前面的答案不适用于 Hooks。在这种情况下,将第二个参数传递给 setState
Warning: State updates from the useState() and useReducer() Hooks don't support the second callback argument. To execute a side effect after rendering, declare it in the component body with useEffect().
如错误消息所述,在这种情况下您需要使用 useEffect
(另请参阅
我知道这是关于 class 组件的...但是在功能组件中我这样做是为了同步设置状态:
const handleUpdateCountry(newCountry) {
setLoad(() => true);
setCompanyLocation(() => newCountry);
setLoad(() => false);
}
刚刚为我的自动国家/地区检测工作,应该将表单设置为脏。
任何其他答案中都没有提到的一种方法是将操作包装在 setTimeout 中。如果您使用钩子,这也将起作用。
例如:
handleChange(input) {
this.setState({ load: true })
setTimeout(() => {
this.props.actions.getItemsFromThirtParty(input).finally(() => {
this.setState({ load: false })
});
});
}