The course is part of this learning path
This module looks at how to manage state in React. You’ll be looking at state management, context, and reducers.
The objectives of this module are to provide you with an understanding of:
- State Management
- How to create and provide context
- How to provide dispatch
This learning path is aimed at all who wish to learn how to use the ReactJS framework.
We welcome all feedback and suggestions - please contact us at email@example.com to let us know what you think.
The useReducer hook is one of the hooks built into React. It's an alternative to the useState hook. It needs to be passing reducer function, and can be optionally passed in an initial state. Whereas the state value in useState is paired with a set function, the useReducer state value is paired with a dispatch function. It's the dispatch function that allows the sending of action objects to update the state. It's widely accepted that useReducer is preferred to useState when there's complex state logic. The next state may depend on the previous one, and or there may be a number of sub-values. It helps in complex component structures because the dispatch function can be provided rather than passing a callback through multiple layers using props. Calling dispatch has the same rendering effect as calling setState. On a performance note, if the dispatch call produces the same status before, React won't re-render child components or fire any effects. React may need to render the specific component again though before bailing out. If we do the mistake for a provider component, the useReducer hook can be used here. The example shown has useReducer pass the myReducer function, and setting state to initialState. Instead of the value attribute of the context provider being a static value, it's now whatever the useReducer hook has returned as the state value. As this is a component, you could use a useEffect hook to make a call after its initial render to get some asynchronous data. The effect could then call dispatch with the action, and a payload of that return data. So here, we show the code to allow the course data to be once again retrieved from our RESTful endpoint. The first thing we'll look at here is how we actually make that call. It's in the getCourses function defined between lines 20 and 37. The main job of this function is to get the payload for the action getCourses. The majority of this code is from the getCourses function that had been used in the filterable courses table setting of state. The function is still async, and we make a fetch call to the data endpoint. We handle a good response by setting payload to respond stock JSON. When we handle non-good responses, we set a payload to be an array with an object that has a status and a message in it. Remember the filterable courses table will look for a course array with its first element as an object with a status of key. Well, that's done now, and will display error components. We've surrounded the whole response handling in a try block. And if we get an error not related to the status, we set a payload to a 503 status with a message for it. At the end of the function, we return the payload. So that's how we actually get the data. We've extended the CoursesProvider component on lines 39 to 57. To include the useReducer hook, we pass the coursesReducer function in, and set the initial state to be an object that has a courses key and an empty array. That's how the loading message can be displayed whilst we wait for the data to arrive. There's a useEffect hook in this component too. That defines an async function that sets the payload by awaiting the return of the getCourses function. Once we have that data, we call dispatch with the action object. That's set to have a type of getCourses, and of course, our payload. Dispatch fires the coursesReducer function, and you can see that we've now put a return on the getCourses action type to construct an object taking the previous state, and adding a key of courses with the actions payload as the value. When we look at the app in the browser now, we can see that the course data has been provided using context. And the state of the context is set by the reducer. That is shown in the dev tools on the right, where the coursesProvider component is showing that it has a reducer hook. This has the courses array within it. Let's refresh the app. We've left the timeout on the async call so you can see what happens is the data is waited on. If we turn off the JSON server and refresh the app again, you can see that the 503 error is returned. So now we've been able to use contacts and reducers to provide data by a state in a component that's only there for doing just that. But to make the Submit function of the form work using the reducer, we need to look at providing the dispatch function, so it can be fired somewhere other than the coursesProvider component.