当前位置: 首页 > 科技观察

React中请求远程数据的四种方式

时间:2023-03-13 16:50:26 科技观察

React是一个专注的组件库。因此,它对如何请求远程数据几乎没有什么建议。如果您想通过HTTP请求数据并将其发送到WebAPI,可以考虑以下四种方法。内联编写集中管理自定义Hookreact-query/swr注意:在本文中,我将使用fetch进行HTTP调用,但这些模式也适用于Axios等替代方案。此外,如果您使用的是GraphQL,还可以考虑其他不错的选择,例如Apollo。这篇文章假设您正在调用传统的RESTAPI。方式1:内联这是最简单直接的选择。在React组件中进行HTTP调用和处理响应。fetch("/users").then(response=>response.json());看起来很简单。但是这个例子忽略了加载状态、错误处理、声明和设置相关状态等。在现实世界中,HTTP调用看起来更像这样。importReact,{useState,useEffect}from"react";exportdefaultfunctionInlineDemo(){const[users,setUsers]=useState([]);const[loading,setLoading]=useState(true);const[error,setError]=useState(null);useEffect(()=>{fetch(`${process.env.REACT_APP_API_BASE_URL}users`).then(response=>{if(response.ok)returnresponse.json();throwresponse;}).then(json=>{setUsers(json);}).catch(err=>{console.error(err);setError(err);}).finally(()=>{setLoading(false);});},[]);if(loading)return"Loading...";if(error)return"Oops!";returnusers[0].username;}对于一个简单的应用,只要发出几个请求,就可以正常工作。但是上面的状态声明和useEffect是模板。如果我要进行多次HTTP调用,我不想为每次调用重复和维护约20行代码。内联调用使您的代码变得丑陋。看看我们试图解决的一些问题:声明一个加载状态声明一个错误状态向控制台打印错误检查响应是否通过返回200response.ok如果响应正常,将响应转换为json并返回一个promise如果响应不正确,则抛出一个错误在finally中隐藏加载状态,以确保即使发生错误也隐藏加载声明一个空的dependencies数组,以便useEffect只运行一次这只是一个简单的例子,忽略了许多其他相关问题。方法2:集中文件夹管理如果我们在一个文件夹中处理所有HTTP调用会怎么样?使用这种方法,我们创建了一个名为services的文件夹,并将进行HTTP调用的函数放入其中。服务是更流行的术语,我还在下面讨论了很多好的替代方案,比如客户端或API。要点是所有HTTP调用都由存储在文件夹中的纯JavaScript函数处理。这是一个集中式的getUsers函数:exportfunctiongetUsers(){returnfetch(`${process.env.REACT_APP_API_BASE_URL}users`).then(response=>response.json());}这是对getUsers函数的调用:importReact,{useState,useEffect}from"react";import{getUsers}from"./services/userService";exportdefaultfunctionCentralDemo(){const[users,setUsers]=useState([]);const[loading,setLoading]=useState(true);const[error,setError]=useState(null);useEffect(()=>{getUsers().then(json=>{setUsers(json);setLoading(false);}).catch(err=>{console.error(err);setError(err);});},[]);if(loading)return"Loading...";if(error)return"Oops!";returnusers[0].username;然而,这并没有过多地简化请求调用。主要好处是它强制执行对HTTP调用的一致处理。这个想法是这样的:当相关的功能一起处理时,更容易一致地处理它们。如果userService文件夹中充满了进行HTTP调用的函数,我可以轻松地确保它们始终如一地进行。此外,如果调用被重复使用,则很容易从这个集中位置调用它们。然而,我们可以做得更好。方法三:自定义Hook有了ReactHooks的魔力,我们终于可以专注于重复的逻辑了。那么如何创建一个自定义的useFetch钩子来简化我们的HTTP调用呢?import{useState,useEffect,useRef}from"react";//ThiscustomhookcentralizesandstreamlineshandlingofHTTPcallsexportdefaultfunctionuseFetch(url,init){const[data,setData]=useState(null);const[loading,setLoading]=useState(true);const[error,setError]=useState(null);constprevInit=useRef();constprevUrl=useRef();useEffect(()=>{//Onlyrefetchifurlorinitparamschange.if(prevUrl.current===url&&prevInit.current===init)return;prevUrl.current=url;prevInit.current=init;fetch(process.env.REACT_APP_API_BASE_URL+url,init).then(response=>{if(response.ok)returnresponse.json();setError(response);}).then(data=>setData(data)).catch(err=>{console.error(err);setError(err);}).finally(()=>setLoading(false));},[init,url]);return{data,loading,error};}你的可能看起来不一样,但我发现这个基本用法很有用。这个Hook大大简化了所有调用。查看使用此Hook需要多少代码:importReactfrom"react";importuseFetchfrom"./useFetch";exportdefaultfunctionHookDemo(){const{data,loading,error}=useFetch("users");if(loading)return"Loading..";if(error)return"Oops!";returndata[0].username;}对于许多应用程序,您只需要一个这样的自定义Hook。但是这个Hook已经很复杂了,省去了很多问题。但是还有很多点我们没有考虑到:缓存?,如果客户端的连接不可靠,如何重新获取?当用户重新调整选项卡时,您是否希望再次获取新数据?如何消除重复查询?你可以不断完善这个self定义的Hooks来完成所有这些操作。但是,你应该只需要方式四:方式四:react-query/swr使用react-query或者swr,它为我们处理缓存、重试、重复查询等。我不必再维护自己的自定义Hook。每个HTTP调用只需要很少的代码:importReactfrom"react";import{getUsers}from"./services/userService";import{useQuery}from"react-query";exportdefaultfunctionReactQueryDemo(){const{data,isLoading,error}=useQuery("users",getUsers);if(isLoading)return"Loading...";if(error)return"Oops!";returndata[0].username;}对于大多数应用程序,这是我今天的首选.这里是完整的代码:https://codesandbox.io/s/4-ways-to-handle-restful-http-in-react-k3xug,大家可以自己对比一下。