setState 回调未按预期工作
setState callback not working as expected
我有一个正在运行的应用程序,我只是想在我的应用程序调用提交时将状态设置为 loading: true
,这样我就可以显示加载屏幕。因为我想确保在 进行加载调用之前 设置状态,所以我使用了回调。但是我没有看到我使用以下代码进行加载更新:
submitSecurityAnswer = () => {
const { submit, handleError, navigate } = this.props;
const { answer } = this.state;
this.setState({ loading: true }, () => {
console.log('setState', this.state)
try {
submit({ answer, ...this.props }).then(({ errors, status }) => {
this.setState({ answer: '' });
if (status && status === 200) {
navigate();
} else if (status === 401) {
this.setState({ showError: true });
} else {
handleError(errors[0]);
}
});
} catch (err) {
console.log(err);
}
});
this.setState({ loading: false });
};
当我检查我的控制台日志时,我发现状态没有更新,加载仍然是错误的。
我在这里错过了什么?
那是因为您在异步操作完成之前将 loading
设置为 false
。
只需将 this.setState({ loading: false });
移到 callback
;
内
编辑
作为您评论的跟进:
I tried removing that but saw the same results
我没说要删除它只是 在 setstate
的回调中移动 它。
发生的情况是您在同一调用堆栈迭代中将其设置为 true
然后 false
而不是等待异步操作完成。
考虑与您的代码类似的场景:
在此示例中,我在异步操作 (setTimeout
) 完成之前将 loading
设置回 false,因此我只是在不等待的情况下覆盖之前的状态。
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
message: ''
};
}
componentDidMount() {
this.setState({ loading: true }, () => {
console.log(this.state);
setTimeout(() => {
this.setState({
message: 'we have data'
});
console.log(this.state);
}, 500);
});
this.setState({ loading: false });
}
render() {
const {message, loading} = this.state;
return (
<div>
{loading ? <div>Loading...</div> : <div>{message}</div>}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
解决方法是将下一个状态更改移到回调中:
在这个例子中,我在异步操作完成后将 this.setState({ loading: false });
行移到了回调中,这修复了不需要的行为。
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
message: ''
};
}
componentDidMount() {
this.setState({ loading: true }, () => {
console.log(this.state);
setTimeout(() => {
this.setState({
message: 'we have data'
});
this.setState({ loading: false });
}, 500);
});
}
render() {
const {message, loading} = this.state;
return (
<div>
{loading ? <div>loading...</div> : <div>{message}</div>}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
发生这种情况,因为您在函数末尾调用 this.setState({ loading: false });
。
您正在同时设置 loading: true
和 loading: false
。当您调用回调时,最后一个 setState 函数也将状态值更改为 false。
您应该在收到请求后将加载状态设置为 false:
submitSecurityAnswer = () => {
const { submit, handleError, navigate } = this.props;
const { answer } = this.state;
this.setState({ loading: true }, () => {
console.log('setState', this.state)
try {
submit({ answer, ...this.props }).then(({ errors, status }) => {
this.setState({ answer: '' });
if (status && status === 200) {
navigate();
} else if (status === 401) {
this.setState({ showError: true, loading: false });
} else {
handleError(errors[0]);
}
});
} catch (err) {
console.log(err);
}
});
};
我有一个正在运行的应用程序,我只是想在我的应用程序调用提交时将状态设置为 loading: true
,这样我就可以显示加载屏幕。因为我想确保在 进行加载调用之前 设置状态,所以我使用了回调。但是我没有看到我使用以下代码进行加载更新:
submitSecurityAnswer = () => {
const { submit, handleError, navigate } = this.props;
const { answer } = this.state;
this.setState({ loading: true }, () => {
console.log('setState', this.state)
try {
submit({ answer, ...this.props }).then(({ errors, status }) => {
this.setState({ answer: '' });
if (status && status === 200) {
navigate();
} else if (status === 401) {
this.setState({ showError: true });
} else {
handleError(errors[0]);
}
});
} catch (err) {
console.log(err);
}
});
this.setState({ loading: false });
};
当我检查我的控制台日志时,我发现状态没有更新,加载仍然是错误的。
我在这里错过了什么?
那是因为您在异步操作完成之前将 loading
设置为 false
。
只需将 this.setState({ loading: false });
移到 callback
;
编辑
作为您评论的跟进:
I tried removing that but saw the same results
我没说要删除它只是 在 setstate
的回调中移动 它。
发生的情况是您在同一调用堆栈迭代中将其设置为 true
然后 false
而不是等待异步操作完成。
考虑与您的代码类似的场景:
在此示例中,我在异步操作 (setTimeout
) 完成之前将 loading
设置回 false,因此我只是在不等待的情况下覆盖之前的状态。
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
message: ''
};
}
componentDidMount() {
this.setState({ loading: true }, () => {
console.log(this.state);
setTimeout(() => {
this.setState({
message: 'we have data'
});
console.log(this.state);
}, 500);
});
this.setState({ loading: false });
}
render() {
const {message, loading} = this.state;
return (
<div>
{loading ? <div>Loading...</div> : <div>{message}</div>}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
解决方法是将下一个状态更改移到回调中:
在这个例子中,我在异步操作完成后将 this.setState({ loading: false });
行移到了回调中,这修复了不需要的行为。
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
message: ''
};
}
componentDidMount() {
this.setState({ loading: true }, () => {
console.log(this.state);
setTimeout(() => {
this.setState({
message: 'we have data'
});
this.setState({ loading: false });
}, 500);
});
}
render() {
const {message, loading} = this.state;
return (
<div>
{loading ? <div>loading...</div> : <div>{message}</div>}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
发生这种情况,因为您在函数末尾调用 this.setState({ loading: false });
。
您正在同时设置 loading: true
和 loading: false
。当您调用回调时,最后一个 setState 函数也将状态值更改为 false。
您应该在收到请求后将加载状态设置为 false:
submitSecurityAnswer = () => {
const { submit, handleError, navigate } = this.props;
const { answer } = this.state;
this.setState({ loading: true }, () => {
console.log('setState', this.state)
try {
submit({ answer, ...this.props }).then(({ errors, status }) => {
this.setState({ answer: '' });
if (status && status === 200) {
navigate();
} else if (status === 401) {
this.setState({ showError: true, loading: false });
} else {
handleError(errors[0]);
}
});
} catch (err) {
console.log(err);
}
});
};