Four ways to request remote data: 1. Make HTTP calls directly in the React component and process the response; 2. Create a folder, put all the functions that make HTTP calls into it, and centrally request data and process it. Response; 3. Customize Hook to request data; 4. Use "react-query" or swr to request data.
The operating environment of this tutorial: Windows7 system, react17.0.1 version, Dell G3 computer.
React
is a dedicated component library. Therefore, it has few suggestions on how to request remote data. If you want to request data via HTTP
and send it to Web API
, here are four methods to consider.
Inline writing
Centralized management
CustomizationHook
react-query/swr
Note: In this article, I will use fetch makes HTTP calls, but these patterns also apply to alternatives like Axios. Alternatively, if you are using GraphQ L, there are other good options to consider like Apollo. This article assumes you are calling a traditional REST API.
This is the simplest and most direct option. Make the HTTP
call and handle the response in the React
component.
fetch("/users").then(response => response.json());
Looks simple. But this example ignores loading status, error handling, declaring and setting related status, etc. In the real world, a HTTP
call would look more like this.
import React, { useState, useEffect } from "react"; export default function InlineDemo() { 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) return response.json(); throw response; }) .then(json => { setUsers(json); }) .catch(err => { console.error(err); setError(err); }) .finally(() => { setLoading(false); }); }, []); if (loading) return "Loading..."; if (error) return "Oops!"; return users[0].username; }
For a simple application, just make a few requests and it will work fine. But the above state declaration and useEffect
are both templates. If I'm going to make many HTTP
calls, I don't want to repeat and maintain about 20 lines of code for each call. Inline calls make your code look ugly.
Look at some of the issues we want to solve:
Declare loading status
Declare error status
Print the error to the console
Check if the response passes and return 200 response.ok
If the response is OK, convert the response to json
and return promise
If the response is incorrect, throw an error
Hide the loading state in finally
to ensure that Loading
is hidden even if an error occurs
useEffect only runs once
This is just a simple example that ignores many other related issues.Method 2: Folder centralized managementWhat if we handle all
HTTP calls in one folder? Using this method, we create Create a folder named
services and put all the functions that make HTTP calls into it.
service is the most popular term, I have also discussed a lot of good alternative names below such as
client or
api.
HTTP calls are handled through pure
JavaScript functions, stored in a folder. This is a centralized
getUsers function:
export function getUsers() { return fetch(`${process.env.REACT_APP_API_BASE_URL}users`).then(response => response.json() ); }
getUsers function:
import React, { useState, useEffect } from "react"; import { getUsers } from "./services/userService"; export default function CentralDemo() { 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!"; return users[0].username; }
HTTP calls. The idea is this: when related functions are processed together, it's easier to process them consistently. If the
userService folder is full of functions making
HTTP calls, I can easily make sure they do so consistently. Additionally, if calls are reused, they are easily invoked from this centralized location.
React Hooks, we can finally focus on processing repetitive logic. So how do we create a custom
useFetch hook to simplify our
HTTP calls?
import { useState, useEffect, useRef } from "react"; // This custom hook centralizes and streamlines handling of HTTP calls export default function useFetch(url, init) { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const prevInit = useRef(); const prevUrl = useRef(); useEffect(() => { // Only refetch if url or init params change. 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) return response.json(); setError(response); }) .then(data => setData(data)) .catch(err => { console.error(err); setError(err); }) .finally(() => setLoading(false)); }, [init, url]); return { data, loading, error }; }
Hook :
import React from "react"; import useFetch from "./useFetch"; export default function HookDemo() { const { data, loading, error } = useFetch("users"); if (loading) return "Loading..."; if (error) return "Oops!"; return data[0].username; }
使用 react-query或swr
,可以为我们处理缓存、重试、重复查询等等。我不必维护自己的自定义Hook了。而且每个 HTTP
调用都需要很少的代码:
import React from "react"; import { getUsers } from "./services/userService"; import { useQuery } from "react-query"; export default function ReactQueryDemo() { const { data, isLoading, error } = useQuery("users", getUsers); if (isLoading) return "Loading..."; if (error) return "Oops!"; return data[0].username; }
对于大多数应用程序来说,今天这是我的首选。这是完整的代码:https://codesandbox.io/s/4-ways-to-handle-restful-http-in-react-k3xug
,你可以自己进行比较。
推荐学习:《react视频教程》
The above is the detailed content of What are the four methods to request remote data in react. For more information, please follow other related articles on the PHP Chinese website!