Blog>
Snippets

Synchronizing Router State with Redux v5.0.1

A code pattern exemplifying how to synchronize React Router state with the Redux state tree in v5.0.1, providing seamless navigation experience.
import { createSlice } from '@reduxjs/toolkit';
import { push } from 'connected-react-router';

// Define the initial state of the router slice
const initialState = {
    location: null,
    action: null,
};

// Create a slice for the router state with Redux Toolkit
const routerSlice = createSlice({
    name: 'router',
    initialState,
    reducers: {
        // Reducer to synchronize the router state change
        locationChange: (state, action) => {
            state.location = action.payload.location;
            state.action = action.payload.action;
        },
    },
});

// Export the reducer
export const { locationChange } = routerSlice.actions;
export default routerSlice.reducer;
This piece of code creates a Redux slice for handling the router state using Redux Toolkit's createSlice. It includes an initial state and a reducer 'locationChange' for updating the router state within the Redux store.
import { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { useLocation, useHistory } from 'react-router-dom';
import { locationChange } from './routerSlice'; // Import the locationChange action from the router slice

// Custom hook to synchronize the router state with Redux
const useSyncRouterWithRedux = () => {
    const dispatch = useDispatch();
    const location = useLocation();
    const history = useHistory();

    useEffect(() => {
        // On location change, dispatch an action to update the Redux state
        const handleLocationChange = (location, action) => {
            dispatch(locationChange({ location, action }));
        };

        // Subscribe to history changes
        const unsubscribe = history.listen(handleLocationChange);

        // Call handler for the initial location
        handleLocationChange(location, history.action);

        // Cleanup the listener on unmount
        return unsubscribe;
    }, [dispatch, location, history]);
};

export default useSyncRouterWithRedux;
This piece of code demonstrates a custom React hook 'useSyncRouterWithRedux' that uses React Router's 'useLocation' and 'useHistory' hooks to listen for route changes. It dispatches 'locationChange' actions to sync the router state with the Redux store.
import { Provider } from 'react-redux';
import { BrowserRouter as Router } from 'react-router-dom';
import { configureStore } from '@reduxjs/toolkit';
import rootReducer from './rootReducer';
import useSyncRouterWithRedux from './useSyncRouterWithRedux';

// Create the Redux store with the root reducer
const store = configureStore({
    reducer: rootReducer,
});

const App = () => {
    // Use the custom hook inside the App component
    useSyncRouterWithRedux();

    return (
        <Provider store={store}>
            <Router>
                {/* App routes and components */}
            </Router>
        </Provider>
    );
};

export default App;
This piece of code sets up a React component 'App' that includes the Redux Provider and the Router. It uses the 'useSyncRouterWithRedux' hook to keep the router state in sync with the Redux store.