React useEffect and async fetch
这是我的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | const useMyFetch = (url, options) => { const [response, setResponse] = React.useState(null); React.useEffect(() => { console.log("going to fetch", url); fetch(url, options).then(async function(response) { var json = await response.json(); setResponse(json.message); }); }, [ url ]); return response; }; function Example() { const res = useMyFetch("https://dog.ceo/api/breeds/image/random", { method: 'GET' }); if (!res) { return loading... } return <img src={res} alt="an image" />; } |
看起来一切都很好...除非我将useEffect的第二个参数从[url]替换为[url,options]。
当存在\\'options \\'时,我们将进入众所周知的无限循环...但是将其包含在此数组中是合乎逻辑的。这怎么了
谢谢
将
1 2 3 4 5 | const options = { method: 'GET' }; function Example() { const res = useMyFetch("https://dog.ceo/api/breeds/image/random", options); ... } |
否则,每次
正如@Titus已经提到的,这是因为
选项1。我们可以使用
1 2 3 4 | function useMyFetch(url, options) { useEffect(() => { }, [url, JSON.stringify(options)]) } |
选项2。我们可以使用
1 2 3 4 5 6 7 | function useMyFetch(url, options) { const prevOptions = useRef(null); useEffect(() => { ... prevOptions.current = options; }, [url, customCompare(options, prevOptions.current)]) } |
选项3。最后,我可以创建自定义钩子,如果所有嵌套属性都相等,则该钩子将返回引用相同的对象:
1 2 3 4 5 6 7 8 | function useObject(obj) { const prevObj = useRef(obj); const isEqual = _.isEqual(prevObj.current, obj); useEffect(() => { prevObj.current = obj; }, [isEqual]); return isEqual ? prevObj.current : obj; } |
,以后用作
1 2 3 4 5 6 7 8 9 10 11 12 | function Example() { const requestOptions = useObject({ method: 'GET' }); const res = useMyFetch("https://dog.ceo/api/breeds/image/random", requestOptions); if (!res) { return loading... } return <img src={res} alt="an image" />; } |
选项4。最直接的方法是将对象
1 2 3 4 5 | function useMyFetch(url, options) { const {method, headers: {contentType} = {} , ...rest } = options; useEffect(() => { }, [url, method, contentType, JSON.stringify(rest)]); } |
我相信虽然此方法比上面的方法更为详尽,但它会稍微快一些,特别是如果
查看要测试的URL显示图像
它应该返回setResponse您想要的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | const useMyFetch = (url, options) => { const [response, setResponse] = React.useState(null); React.useEffect(() => { console.log("going to fetch", url); fetch(url, options).then(async (response)=> { var json = await response.json(); return setResponse(json.message); }); }, [ url ]); return response; }; function Example() { const res = useMyFetch("https://dog.ceo/api/breeds/image/random", { method: 'GET' }); if (!res) { return loading... } return <img src={res} alt="an image" />; } export default Example; |