The usual way to share data between two components in react is through passing the data as props from parent to children.
Let us consider a counter parent component with three child components.
The child components would be :
The updating counter
Increasing button(to increase the counter value)
Decreasing button(to decrease the counter value)
Lets first consider the Redux approach.
Redux
Redux is all about dispatching actions which then change a central store causing the store to update the values.
The redux state management needs the following:
actions
reducers
store
Actions : Actions are the only source of information for the store as per the redux official documentation.It carries payload of information from your application to store.Actions are plain javascript object that must have a type attribute to indicate the type of action performed.
//actions
export const increment = () => {
return {
type : 'INCREMENT_COUNT'
}
}
export const decrement = () => {
return {
type:'DECREMENT_COUNT'
}
}
Reducers : Actions only tell what to do,but they don't tell how to do,so reducers are the pure functions that take the current state and action and return the new state and tell the store how to do it.
The reducer uses a switch case that determine the action type,update the state and return the new state.
//reducers
var initState = {
counter : 0
}
const counter = (state=initState,action) => {
switch(action.type) {
case 'INCREMENT_COUNT':
return {
...state,
counter:state.counter+1
}
case 'DECREMENT_COUNT':
return {
...state,
counter:state.counter-1
}
default :
return state
}
}
export default counter
Store : The store is an immutable object tree in Redux.A store is a state container which holds the application's state.Redux can have only a single store in your application.
//store
import { createStore } from 'redux';
import rootReducer from '../reducers/index';
export const store = createStore(rootReducer);
Now we need to make the store accessible to app hence we will wrap the counter app inside the component.
//main app import the necessary
export const ReduxMethod = () => {
return (
<Provider store={store}>
<Counter />
</Provider>
);
}
To access the state and dispatch actions we can use the useSelector and useDispatch hooks.
Now lets see the context approach.
Context
Context can be provided at some point in the app,it can be the root app component or another component and all the child component of the provided component will have access to that context.It provides a way to pass data across the component tree without having to pass props down at every level.
The context approach is much simpler when compared to the redux approach.The value in a context can be updated using a useState hook but since we have already seen the reducer functions let us use the same to update the state.
const countReducer = (state=initState,action) => {
switch(action.type) {
case 'INCREMENT_COUNT':
return {
...state,
counter:state.counter+1
}
case 'DECREMENT_COUNT':
return {
...state,
counter:state.counter-1
}
default :
return state
}
}
export default countReducer
For Context functionality we need to :
create the context
provide the context
consume the context
Creating the context :
A context is created using the createContext() and pass the initial state as arguments.Context can also be defined with passing any arguments.
define a function to pass the data through the provider
In the provider functions,use useReducer and pass the initial state and the reducer which will be passed as values in the provider.
//countState
const initState = {
counter:0
}
export const CounterContext = createContext(initState);
export const CounterProvider = ({ children }) => {
const [state,dispatch]=useReducer(countReducer,initState);
return (
<CounterContext.Provider value={{ state,dispacth }}>
{children}
</CounterContext.Provider>
);
}
Providing the context : Provide the context to the counter app so that its child components have access to it.
export const ContextMethod = () => {
return (
<CounterProvider>
<Counter />
</CounterProvider
)
}
Consuming the context: We use the useContext to use the values or set the values stored in the context.
Here to use the values the state and dispatch will be used,but whenever we use it we need to use the useContext and destructure it in the component.
const { state } = useContext(CounterContext);
//The state value represents the counter value
const {dispatch} = useContext(CounterContext);
//This will be used to update the state.
Note:If we had used the useState instead of the reducer,the setState would be replacing the dispatch.
Now that we have understood the setup of both let us see when to use which.
Context:
In context when we update a particular value the same context used in other components for a different value of the context also re-renders again because context makes every component in the provider to re-render whenever data is changed.
Context is a built-in package of react which means we can use it without increasing the size of our project.
It has a simpler setup to get started with working on it.
Context is great to be used in static or rarely refreshed data.
Redux:
It is more commonly used and hence a lot of problems have been resolved.
Redux is great for often updating data as we can prevent unnecessary re-renders of the components.
Redux is easily integrated with redux via package.
Server side rendering is possible with redux.
Conclusion
In the case of small applications where data isn't changed often Context seems to be a better choice but when application is big and complex and the application state changes often Redux seems to be the winner.
Top comments (0)