In a usual React application, the common way of sharing data between two components is via prop drilling, i.e. passing the data as props from parent component to child component.
The pop drilling method is suitable for a small application with two or three nested child components. However, for complicated applications, the data must be passed down as props to each of the levels until it reaches the desired component. This requires additional code. As the prop is updated in a child component, it must be passed to all the components that require it. Because of this, components that don’t need the data need to be 'aware' of it.
A way around this issue is to provide a global state that all components, regardless of their nested position, could access. This can be achieved using Redux.
Context provides a way to pass data through the component tree without having to pass props down manually at every level.
The example below is based on a Counter component for a Sitecore website. The Counter has an initial value of 0 and two buttons to increase and decrease its value.
Inside the main parent Sitecore Counter component, there are three child components; one for updating the counter and two for each of the buttons. The initial setup would be equal for both methods.
Below examines each component in its respective method using the Redux approach and the Context API approach.
The Redux approach
Redux requires the following blocks to function:
Actions are the only source of information for the Store. Actions carry the information that sends data from the application to the Store. Below is an example of Action creators that dispatch an action:
Reducers are responsible for how the application changes in response to an action made by an end-user. Below is an example of a Reducer with a switch case that would return the new state based on the action:
The Store knits every thing together to make the application work. Below is an example of Store configuration:
To make the Store accessible in the counter app and its children components, it needs to be wrapped inside the <Provider> component.
To access the state and dispatch within Redux, use useSelector() and useDispatch() hooks, which were introduced by React-Redux with version 7.1 after React introduced hooks.
Context API approach
Declaring a Reducer using the Context API approach is the same as Redux.
Other functions in this process include:
- Create the context
- Provide the context
- Consume the context
Create the context
- Create a context using createContext() and pass the initial state as arguments. Context can also be defined without passing any arguments.
- Define a function that will deliver the data through the Provider.
- Using useReducer() hook accepts a Reducer with the default state, then returns the updated state and dispatches a function.
- Inside the provider function, use useReducer() and pass the Reducer and the initial state as arguments. The state returned and dispatch are then passed as values in the Provider.
Provide the context
Now that context has been Created, context needs to be Provided in order to Consume it and make it accessible in the Counter its child components. This is achieved by wrapping it inside the Provider component.
Consume the context
Use useContext() to consume the context in the child components.
Example of Redux and Context API Counter
Redux vs Context API: Comparisons
Context API is easy to is use as it has a short learning curve. It requires less code, and because there's no need of extra libraries, bundle sizes are reduced. Redux on the other hand requires adding more libraries to the application bundle. The syntax is complex and extensive creating unnecessary work and complexity. However, it's still a great alternative regarding prop drilling.
Context API prompts a re-render on each update of the state and re-renders all components regardless. Redux however, only re-renders the updated components. This can be monitored on the console as there's a log in each component.
Redux vs Context API: Conclusions
- Context API: Resourceful and ideal for small applications where state changes are minimal
- Redux: Perfect for larger applications where there are high-frequency state updates
At Codehouse our expert development team is constantly exploring new technologies that will improve the development process and also the end user's digital experience. To find out more about how we help with your Sitecore project, get in touch.