React: Redux
How does Redux work? Redux is a state managing system used for cross-component or app-wide states (data that changes).
Redux has ONE central data store. Components subscribe to the central data store. Components NEVER directly manipulate the store data. Therefore we need Reducer functions to mutate the store data.
Take note that these Reducer functions are NOT the same as useReducer() hooks.
Components dispatch (trigger) actions, which describe what should be done, then these actions are forwarded to the reducer. The reducer then does what the action wants it to do, and outputs a new state which will replace the existing state in the central data store.
When that state in the central data store is updated, subscribing components are notified so that they can update their UI.
How do we then actually use Redux? Firstly, npm install redux react-redux (if not already installed in the project).
Once redux is installed, create a store.
To create a store, we first have to create a folder and a js file.
Within that js file, import createStore from redux. Then call createStore(). createStore needs a pointer to a Reducer function as a parameter.
The Reducer function gets an existing state as the first argument and an action (which will be dispatched) as the second argument.
The state can have a default value as shown in the example above. This will act as an initial state when the reducer is executed for the first time.
Within the function, we handle the different types of actions. In this case, ‘increment’ and ‘decrement’. Each action will return a different state snapshot. The unchanged version of state will be returned if none of the action types are met.
createStore() will now receive this Reducer function as its argument and point at it.
This is how you create a Redux store.
Now we need to connect our React app to this Redux store so that the components of the app can dispatch actions and listen for state updates. In order to do this, we need to provide the store to the React app.
How do we then provide the Redux store to the React app?
Typically we would go into the index.js file, where we render the entire app, i.e. the highest level we can go in our React application.
In there, we import the Provider component, then wrap the root component (<App />) with it.
In order to provide the store we created, we first have to import it.
Then using Provider’s props, we can indicate which is the store that we wish to connect it with.
Since we have set up the connection, we can now access the data in store. In order to do this, we make use of the useSelector hook, which is a custom pre-built-in hook.
We can then call the useSelector. useSelector expects a function. This function will be executed by React Redux. The function receives a state managed by Redux, and returns part of the state from within store which you want to extract.
The upside of using useSelector is, React Redux will automatically set up a subscription to the Redux store for this component which you used it in.
Therefore your component will receive the latest state automatically whenever that data changes in the Redux store and will be updated accordingly.
i.e. Changes to the Redux store will cause the whole component function to be re-executed.
That’s how we can get access to data managed by Redux.
How do we now update the state within the store from within our components? By using the pre-built-in hook, useDispatch().
Firstly, import it, then call it.
We don’t pass any argument into it, but instead, it will give us back a dispatch function that we will be able to execute.
We can then create functions wherein we can execute the dispatch function. Keep in mind that an action is an object with a type property.
The value for the type should be one of the identifiers we used in our Redux store reducer, in this case, ‘increment’ and ‘decrement’ — exactly as we used it there.
The final step is to actually wire it up.
It is also possible to attach payloads to actions.
We can add more properties to it, and the name of the properties are up to us. In this case, it is ‘amount’.
We can then use it within store like the above.
In the end, payloads are just extra properties we can add to our action objects.
It is important to note that existing state should NOT be mutated directly, as shown in the example above (state.counter++), instead, you should always override it and return a brand new state as shown in the prior example.
In the case of objects and arrays, since they are reference values in Javascript, always make sure you create a brand new object or array when updating them. Do NOT work with the existing object.
References:
This is basically a typed version (for my personal studying and understanding purposes and to be of help to anyone studying this too) of the below video and therefore all credit goes to its creator.
- Udemy (React — The Complete Guide (incl Hooks, React Router, Redux) by Maximilian Schwarzmüller)