Hello, explorer! We'll be delving further into React, encountering asynchronous API calls and custom hooks. These tools will enable us to confidently manage states and reuse code.
Asynchronous operations in JavaScript resemble those of a busy astronaut. You'd request supplies (by sending a request) and then proceed with other tasks without waiting for the supplies (response).
The Fetch API
is used to send a GET request, as exemplified below:
JavaScript1//GET request to fetch spaceship data 2fetch('https://api-regional.codesignalcontent.com/spaceships') 3 .then(response => response.json()) 4 .then(data => console.log(data));
In React, just as you reuse components through importing, custom hooks allow you to extract and reuse state logic across different components. Custom hooks, just like normal built-in hooks such as useState
or useEffect
, can hold data throughout component re-renders, triggering rendering updates when the state changes.
Let's create a custom hook named useFetchSpaceships
which we'll use to fetch spaceships data:
JavaScript1// The ./useFetchSpaceships.js file that defines a custom hook for fetching spaceship data 2const useFetchSpaceships = url => { 3 // Initialize state variables for storing data and loading status 4 const [data, setData] = useState(null); 5 const [loading, setLoading] = useState(true); 6 7 useEffect(() => { // Use useEffect to execute the data fetching logic upon initial render 8 // Fetch data from the provided URL 9 fetch(url) 10 .then(response => response.json()) 11 .then(data => { 12 // Once data is fetched, save it in the data state and set loading to false 13 setData(data); 14 setLoading(false); 15 }); 16 }, [url]); // Providing URL as a dependency ensures that if the URL changes, useEffect runs again 17 18 return { data, loading }; // Return data and loading status so they can be used in the component that calls this hook 19}; 20export default useFetchSpaceships;
In the above code:
- We create a function
useFetchSpaceships
which takes the URL for our API as a parameter. - We set a state variable
data
which stores the fetched data, andloading
to keep track of when the data is still being fetched. - We use
useEffect
to run our fetch operation once the component mounts. Theurl
specified in the dependency array ensures the operation runs once and subsequently only ifurl
changes. - We fetch the data from the
url
and set this data to ourdata
state variable. We also update ourloading
state to indicate that we've fetched our data. - After the operations are done, we return our
data
andloading
status, which can be used in any component to display the fetched data from the API, or show a loading indicator while the data is being fetched.
You've now created your first custom hook! It's all set for incorporation in other components.
Building upon our newly created useFetchSpaceships
custom hook, let's see how we can use it in a more generalized context - to fetch spaceships data not just from one, but multiple servers.
Just like you create components and import them wherever they're needed, similarly you can import and use hooks across your app. This makes custom hooks extremely adaptable and easy to use in a diverse array of scenarios.
JavaScript1import React from 'react'; 2import useFetchSpaceships from './useFetchSpaceships'; 3 4const MarsSpaceships = () => { 5 // Use the custom hook to fetch Mars spaceship data 6 const {data: spaceships, loading} = useFetchSpaceships('https://api-regional.codesignalcontent.com/spaceships/mars'); 7 8 return loading ? <div>Loading...</div> : <div>{spaceships.map(ship => <p>{ship.name}</p>)}</div>; 9}; 10 11export default MarsSpaceships;
Let's dive deeper into this:
- We import
useFetchSpaceships
from'./useFetchSpaceships'
. This is the file where we defined our custom hook. - In our
MarsSpaceships
functional component, we use theuseFetchSpaceships
custom hook. We give it the URL of the Mars spaceships API. - We assign
data
to thespaceships
variable and keep theloading
variable as it is. This operation uses an interesting JavaScript feature, named destructuring, which simplifies extracting properties from an object. - Finally, our render function utilizes conditional rendering. If the data is still loading, it displays a loading message. Once loading is complete, it cycles through the
spaceships
array and prints the name of each ship.
In this manner, you are not constrained to just one API call. You can create instances of different hooks for varying API calls, enhancing code reuse and efficiency!
Great job! We've explored asynchronous API calls, managed the loading and fetched data states, and learned about custom hooks. Get ready for our upcoming coding tasks. Exciting times await us on our React journey. Happy coding!