📓 4.5.0.6 NY Times API: Implementing useReducer
Now it's time to refactor the TopStories
component to use the useReducer()
hook. Let's first take a look at the updated code, and then review the changes in detail down below.
If you want to take on a challenge, try refactoring the TopStories
component to use the useReducer()
hook by yourself before looking at the updated code below.
// We remove the useState hook and add the useReducer hook.
import React, { useEffect, useReducer } from 'react';
import topStoriesReducer from './../reducers/top-stories-reducer';
// We import our action creators.
import { getTopStoriesFailure, getTopStoriesSuccess } from './../actions/index';
// We create initial state for the useReducer hook.
const initialState = {
isLoaded: false,
topStories: [],
error: null
};
function TopStories () {
// We initialize the useReducer hook.
const [state, dispatch] = useReducer(topStoriesReducer, initialState);
useEffect(() => {
fetch(`https://api.nytimes.com/svc/topstories/v2/home.json?api-key=${process.env.REACT_APP_API_KEY}`)
.then(response => {
if (!response.ok) {
throw new Error(`${response.status}: ${response.statusText}`);
} else {
return response.json()
}
})
.then((jsonifiedResponse) => {
// We create an action and then dispatch it.
const action = getTopStoriesSuccess(jsonifiedResponse.results)
dispatch(action);
})
.catch((error) => {
// We create an action and then dispatch it.
const action = getTopStoriesFailure(error.message)
dispatch(action);
});
}, [])
// we destructure error, isLoaded, and topStories from the state variable.
const { error, isLoaded, topStories } = state;
if (error) {
return <h1>Error: {error}</h1>;
} else if (!isLoaded) {
return <h1>...Loading...</h1>;
} else {
return (
<React.Fragment>
<h1>Top Stories</h1>
<ul>
{topStories.map((article, index) =>
<li key={index}>
<h3>{article.title}</h3>
<p>{article.abstract}</p>
</li>
)}
</ul>
</React.Fragment>
);
}
}
export default TopStories;
Let's go over the changes we've made to TopStories.js
. Most of this should be familiar from what we've learned about the useReducer()
hook in the Counter
example.
- First, we need to import
useReducer
from React. We'll also need to remove theuseState
import since we're no longer using it. - Next, we need to import the two action creators that we'll use to generate our actions:
getTopStoriesFailure
andgetTopStoriesSuccess
. - Next, outside of the
TopStories
component, we create our initial state that will be added as an argument to theuseReducer()
hook. We could instead put the initial state in a separate file, or even intop-stories-reducer.js
, and import it intoTopStories.js
. Whatever you do, you should be consistent across your entire application. - We remove the three
useState()
statements and replace them with auseReducer()
hook, passing in theinitialState
andtopStoriesReducer
. We save the state and dispatch function that's returned from theuseReducer()
hook in the variablesstate
anddispatch
; remember that we can call these variables anything so long as it is descriptive of what it represents. - Later in the
useEffect()
hook and API call logic, when we receive a successful response or a failure response, we use either of our two action creator functions to generate an action, and then we dispatch that action using thedispatch()
function. - Finally, the last step in this refactor is to destructure the
error
,isLoaded
, andtopStories
variables from thestate
variable.
Now we can run our application and everything will be working correctly. In other words, our API application is complete! We now have the tools to make API calls with fetch()
in React applications with both the useState()
and useReducer()
hooks.
Next Steps
As you build React apps, we encourage you to continue to use hooks to manage state and avoid class components. That includes whether you use hooks in conjunction with a state library like Redux, or standalone. If you would like to learn how to make an API call in a class component, visit the React docs.
Also, keep in mind that there are many, many custom React hooks out there. Check out this excellent list of resources on hooks, which includes tutorials and links to various custom hooks. Among other things, these custom hooks offer the following additional functionality to function components:
- Handling form state
- Using the Fetch API
- Drawing SVGs
- Handling media queries