说说竞态
上面是一个典型的在 class 组件里发申请的例子:
class Article extends Component {
state = {article: null};
componentDidMount() {this.fetchData(this.props.id);
}
async fetchData(id) {const article = await API.fetchArticle(id);
this.setState({article});
}
// ...
}
你很可能曾经晓得,下面的代码潜伏了一些问题。它并没有解决更新的状况。所以第二个你可能在网上找到的经典例子是上面这样的:
class Article extends Component {
state = {article: null};
componentDidMount() {this.fetchData(this.props.id);
}
componentDidUpdate(prevProps) {if (prevProps.id !== this.props.id) {this.fetchData(this.props.id); } } async fetchData(id) {const article = await API.fetchArticle(id);
this.setState({article});
}
// ...
}
这显然好多了!但仍旧有问题。有问题的起因是申请后果返回的程序不能保障统一。比方我先申请 {id: 10}
,而后更新到 {id: 20}
,但{id: 20}
的申请更先返回。申请更早但返回更晚的状况会谬误地笼罩状态值。
这被叫做竞态,这在混合了async
/ await
(假如在期待后果返回)和自顶向下数据流的代码中十分典型(props 和 state 可能会在 async 函数调用过程中产生扭转)。
Effects 并没有神奇地解决这个问题,只管它会正告你如果你间接传了一个async
函数给 effect。(咱们会改善这个正告来更好地解释你可能会遇到的这些问题。)
如果你应用的异步形式反对勾销,那太棒了。你能够间接在革除函数中勾销异步申请。
或者,最简略的权宜之计是用一个布尔值来跟踪它:
function Article({id}) {const [article, setArticle] = useState(null);
useEffect(() => {
let didCancel = false;
async function fetchData() {const article = await API.fetchArticle(id);
if (!didCancel) {setArticle(article);
}
}
fetchData();
return () => { didCancel = true;}; }, [id]);
// ...
}