useEffect是很常见的,现在写的是十分需求的。
useEffect(async()=>{ awaitgetPoiInfo();//请求数据 },[]);
可是React 却无法支持这样做,就是因为 effect function 应该返回一个销毁函数(effect:是指return返回的cleanup函数),如果 useEffect 第一个参数传入 async,返回值则变成了 Promise,会导致 react 在调用销毁函数的时候报错 :function.apply is undefined。
React为什么这么设计呢?
1、useEffect 的返回值是要在卸载组件时调用的,React 需要在 mount 的这样才可以获取值。
2、useEffect() 似乎有个潜在逻辑:第二次触发 useEffect 里的回调前,前一次触发的行为都执行完成,返回的清理函数也执行完成。这样逻辑才清楚。而如果是异步的,情况会变得很复杂,可能会很容易写出有 bug 的代码。
下面有两种改进的方法大家可以参考下:
简单改造
1、简单改造的写法(不推荐)
第一种 在内部创建一个异步函数anyNameFunction,之后就是等待,在后来就是调用setData
可也有一个问题要知道,就是在asyncFunction请求有依赖外部的参数,不更新requestData 的 effect 的依赖,effect 就不会同步 props 和 state 带来的变更,也就不回重新请求数据
useEffect(() => { // Create an scoped async function in the hook // 注意如果函数没有使用组件内的任何值,可以把它提到组件外面去定义 // 下面代码可以提到外面,可以自由地在 effect 中使用,下面就不改啦 async function asyncFunction() { await requestData(); setData(data) } // Execute the created function directly anyNameFunction(); }, []); // 这里设置成[]数组,因为我们只想在挂载的时候运行它一次
或者 useEffect中异步函数采用IIFE写法( Immediately Invoked Function Expression即立即调用的函数式表达式)
useEffect(() => { // Using an IIFE (async function anyNameFunction() { await requestData(); })(); }, []);
2、把异步提取成多带带函数或自定义hook(推荐)
第一种自定义 hook包裹,然后再effect中通过promise.then调用(github上大佬给的答案:github)
// 自定义hook function useAsyncEffect(effect: () => Promise<void | (() => void)>, dependencies?: any[]) { return useEffect(() => { const cleanupPromise = effect() return () => { cleanupPromise.then(cleanup => cleanup && cleanup()) } }, dependencies) } // 使用 useAsyncEffect(async () => { const count = await fetchData() setCount(count) }, [fetchData])
或者利用useCallback 包装成hook
useCallback 本质上是添加了一层依赖检查,使用useCallback,函数完全可以参与到数据流中,可以说如果一个函数的输入改变了,这个函数就改变了,如果没有,函数也不会改变。
下面的例子中会依赖 type ,如果 type 保持不变,requestData 也会保持不变,effect 也不会重新运行,但是如果 type 修改了,requestData 也会随之改变,因此会重新请求数据。
// 封装 const requestData = useCallback(async () => { changeLoading(true); changeError(false); changeList([]); requestAPI.getFeature({ type }).then((data) => { if (data) { changeList(data); } }).catch((e) => { changeError(true); }).finally(() => { changeLoading(false); }); }, [type]); // type改变会重新生成函数 // 普通接口请求 useEffect(() => { requestData(); }, [requestData]); // 多带带处理外层刷新的接口请求 // refreshing是props传递的过来的,不应该与state状态改变混在一起,这也是hook的优势,将不相关的状态逻辑拆分成更细粒度 useEffect(() => { if (!refreshing) { return; } requestData().then(() => { getRefreshStatus(false); }); }, [refreshing]);
今天讲到这里,后面更多精彩内容欢迎观看。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/128370.html
...可以通过 npm install axios 进行安装。 import React, { useState, useEffect } from "react"; import axios from "axios"; function App() { const [data, setData] = useState({ hits: [] }); useEffect(async () => { const result = await axios( "http://hn.algolia.com/api/v1/search?quer...
...有 setState 开始时有 componentDidMount(和 render props) 使用 useEffect 获取数据 可以使用 React 钩子渲染吗? 第一个自定义 React 钩子 可以使用 async / await 和 useEffect 吗? 结语 附录 1、你将学到什么 如何使用 React 钩子 如何在 React 类...
背景 在使用useEffect中用啦回调函数中使用 async...await... 这时候就会报错。 上面代码可以看到,在报错,effect function 应该返回一个销毁函数(effect:是指return返回的cleanup函数),如果 useEffect 第一个...
...后来实现用于数据获取的effect hook: import React, { useState, useEffect } from "react"; import axios from "axios"; function App() { const [data, setData] = useState({ hits: [] }); useEffect(async () => { const result = await axios( "http://hn.algolia.com/api/v1/search?que...
阅读 58·2023-01-20 08:28
阅读 87·2023-01-20 08:10
阅读 54·2023-01-02 11:07
阅读 32·2023-01-02 10:55
阅读 22·2022-12-25 21:03
阅读 25·2022-12-25 20:37
阅读 44·2022-12-16 17:52
阅读 34·2022-12-16 17:30