说说竞态
上面是一个典型的在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]); // ...}