Context API vs. Redux in a React Application

Cristina Radulescu
METRO SYSTEMS Romania
3 min readJun 20, 2020

In this article I want to make a comparison between state in Redux and state in the Context API.

Redux

The state is maintained in a store which is connected to reducers, actions and middleware. In this example I will use saga middleware for fetching the information from the server and dispatching Redux actions. The store information is then sent to the components using a Provider.

export const sagaMiddleware = createSagaMiddleware();
const store = createStore(eventReducer);
sagaMiddleware.run(rootSaga);
export const EventsConnector = (props) => (
<Provider store={store}>
<AllEvents {...props}/>
</Provider>
);

The Reducer responds to actions being sent to the store.

export const initialState = {
state: null,
events: [],
};
export const eventReducer = (state = initialState, action) => { switch (action.type) {
case FETCH_EVENTS:
return {...state, state: "LOADING"};
case FINISH_FETCHING_EVENTS:
return {...state, events: action.data, state: "LOADED"};
}
return state;
};

The actions startFetchingEvents and finishFetchingEvents will be dispatched to update the state in Redux.

export const FETCH_EVENTS = "FETCH_EVENTS";
export const FINISH_FETCHING_EVENTS = "FINISH_FETCHING_EVENTS";
const createAction = (type, data) => ({ type, data });export const startFetchingEvents = () => createAction(FETCH_EVENTS);export const finishFetchingEvents = (events) => createAction(FINISH_FETCHING_EVENTS, events);

For setting the state an action startFetchingEvents is dispatched which triggers the the saga which after fetching the events from the server will dispatch finishFetchingEvents which will set the events in the Redux state.

export function* fetchAllEventsEffect(action): * {
try {
const response = yield call(fetchEvents);
yield put(finishFetchingEvents(response.data));
} catch (e) {
console.error("Could not load events", e);
yield put(setError(e));
}
}
export default function* fetchAllEvents(): * {
yield takeLatest(FETCH_EVENTS, fetchAllEventsEffect);
}
export function fetchEvents() {
return axios.get('http://localhost:8080/allevents');
}

Context

The state is maintained in the Context and being handed over to the component using a Provider. When the getEvents method is called, the state on the Context will be updated with the response from the server.

const EventContext = createContext();const EventState = props => {
const initialState = {
events: [],
loading: false
};
const [state, dispatch] = useReducer(EventReducer, initialState); const getEvents = async (name) => {
setLoading();
const result = await axios.get('http://localhost:8080/allevents');
const events = result.data;
dispatch({
type: GET_EVENTS,
payload: name ? events.filter(item => (item.name.toLowerCase()).includes(name)) : events
})
};
const setLoading = () => dispatch({type: SET_LOADING}); return (
<EventContext.Provider
value={{
events: state.events,
loading: state.loading,
getEvents,
}}>
{props.children}
</EventContext.Provider>
)
};

The Reducer responds to actions being sent to the store in the same way as this is done in Redux.

export const GET_EVENTS = 'GET_EVENTS';
export const SET_LOADING = 'SET_LOADING';
export default (state, action) => {
switch (action.type) {
case GET_EVENTS:
return {
...state,
events: action.payload,
loading: false
};
case SET_LOADING:
return {
...state,
loading: true
};
default:
return state
}
}

Getting the state from Redux using containers:

export const mapStateToProps = (state) => ({
events: state.eventDetails.events,
});

Getting the state from Context using hooks:

const {events, loading, getEvents} = useContext(EventContext);
useEffect(() => { getEvents();}, []);

My opinion is that for new projects where you need to maintain the state, Context API is a better choice as it makes things a bit simpler than Redux. However, in projects where you are already using Redux, a migration to Context might not really be needed, as in the end both do implementation do the same thing, maintaining state.

You can clone the sample project from here.

In order to start the project you can follow the steps in the Readme. For the calls to server we will be using Mockserver.

Let me know in the comments section below if you already use the Context API and if you find it better than Redux and why.

--

--