Fetch on render lets a React component render before it starts requesting data. The first render can show a spinner; when the response arrives, state updates trigger a second render with the data. section 4.2.3
Loading users into a picker
Initialize users as null, fetch inside useEffect, convert the response to JSON, and call setUsers. Render a Spinner while users is null; otherwise map the users into select options. An empty dependency array runs the request once when the component mounts. section 4.2.3
Use the technique with these rules:
- Keep the effect callback synchronous; define and invoke an async function inside it instead of making the effect itself async. section 4.2.4
- Declare dependencies that control reruns, return cleanup when needed, and separate unrelated side effects into separate effects. section 4.4
- Expect a loading state after the initial render; richer interfaces can reduce opacity or retain a grid while bookings load. section 7.4.4
Listing 4.5 The UserPicker component fetching data
import {useState, useEffect} from "react";
import Spinner from "../UI/Spinner";
export default function UserPicker () {
const [users, setUsers] = useState(null);
useEffect(() => { #1
fetch("http://localhost:3001/users") #2
.then(resp => resp.json()) #3
.then(data => setUsers(data)); #4
}, []); #5
if (users === null) {
return <Spinner/> #6
}
return (
<select>
{users.map(u => (
<option key={u.id}>{u.name}</option>
))}
</select>
);
}
#1 Fetch the data from inside an effect function.
#2 Make the request to the database by using the browser’s fetch API.
#3 Convert the JSON string returned into a JavaScript object.
#4 Update the state with the loaded users.
#5 Include an empty dependency array to load the data once, when the component is first mounted.
#6 Return alternative UI while the users load.
Shows the complete UserPicker implementation, including the request, JSON conversion, state update, loading branch, and rendered options. section 4.2.3
