DEV Community

Cover image for Setting up Redux Toolkit and React Router
chowderhead
chowderhead

Posted on

Setting up Redux Toolkit and React Router

picture cred: https://unsplash.com/@jakobowens1

About me: https://kenchambers.dev/

Feel free to hassle me in the comments if I have any unnecessary code. This post mainly serves as documentation for myself anyways.

create a new redux tool kit app with create-react-app

npx create-react-app my-app --template redux

update RTK boilerplate code

remove all the unessary stuff from App.js

import React from 'react';
import './App.css';

function App() {
  return (
    <div className="App">

    </div>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

now we need to update store.js with the connected-react-router setup. I happen to be using redux thunk in this example but you can use sagas, or whatever you want.

src/app/store.js:

add this to the top of our file: (make sure you have all your dependencies:

yarn add connected-react-router redux-thunk history react-router

import { combineReducers } from '@reduxjs/toolkit';
import { createBrowserHistory } from 'history'
import { connectRouter, routerMiddleware } from 'connected-react-router'
import { applyMiddleware, compose, createStore } from 'redux'
import thunk from "redux-thunk"
import counterReducer from '../features/counter/counterSlice';

Enter fullscreen mode Exit fullscreen mode

I'm going to use the RTK boiler plate reducer so that we can use it as an example of where to put your reducers.

Note: this can be separated into another root-reducer.js file if you like, I just have it all in store.js to make this example quick.

declare and export a const for browser history, and then create a root reducer and add a key for the router.

make sure the key name stays router otherwise it wont work.


export const history = createBrowserHistory()

const createRootReducer = (history) => combineReducers({
  router: connectRouter(history),
  counter: counterReducer
})

Enter fullscreen mode Exit fullscreen mode

lastly lets declare and export the store:

export const store = function configureStore(preloadedState) {
  const store = createStore(
    createRootReducer(history),
    preloadedState, compose(applyMiddleware(routerMiddleware(history), thunk)),
  )
  return store
}
Enter fullscreen mode Exit fullscreen mode

notice how I am also adding thunk to the applyMiddleware function.

all together now: (store.js)


import { combineReducers } from '@reduxjs/toolkit';
import { createBrowserHistory } from 'history'
import { connectRouter, routerMiddleware } from 'connected-react-router'
import blockNodesReducer from '../features/blockNodes/blockNodesSlice';
import { applyMiddleware, compose, createStore } from 'redux'
import thunk from "redux-thunk"

export const history = createBrowserHistory()

const createRootReducer = (history) => combineReducers({
  router: connectRouter(history),
  blockNodes: blockNodesReducer
})

export const store = function configureStore(preloadedState) {
  const store = createStore(
    createRootReducer(history),
    preloadedState, compose(applyMiddleware(routerMiddleware(history), thunk)),
  )
  return store
}


Enter fullscreen mode Exit fullscreen mode

Setup Routing:

navigate over to index.js and import the constants we will need to set up routing:

src/index.js

import { store, history } from './app/store';
import { ConnectedRouter } from 'connected-react-router'
import { Route, Switch } from 'react-router'
Enter fullscreen mode Exit fullscreen mode

now remove what they have in ReactDOM.render and replace it with this :

ReactDOM.render(
  <React.StrictMode>
    <Provider store={store()}>
      <ConnectedRouter history={history}>
        <>
          <Switch>
            <Route exact path="/" render={() => (<App />)} />
            <Route exact path="/test" render={() => (<><h1>test</h1></>)} />
            <Route render={() => (<div>Miss</div>)} />
          </Switch>
        </>
      </ConnectedRouter>
    </Provider>
  </React.StrictMode>,
  document.getElementById('root')
);

Enter fullscreen mode Exit fullscreen mode

notice inside of <Provider> I am calling store() instead of what they had before , where they just imported store without calling it.

Also make sure to import the history object from the file we created earlier: src/app/store.js

Also if you need to use a Context you can pass it directly into <ConnectedRouter> like this:

<ConnectedRouter history={history}>

all together now:

src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { store, history } from './app/store';
import { Provider } from 'react-redux';
import * as serviceWorker from './serviceWorker';
import { ConnectedRouter } from 'connected-react-router'
import { Route, Switch } from 'react-router' // react-router v4/v5

ReactDOM.render(
  <React.StrictMode>
    <Provider store={store()}>
      <ConnectedRouter history={history}>
        <>
          <Switch>
            <Route exact path="/" render={() => (<App />)} />
            <Route exact path="/test" render={() => (<><h1>test</h1></>)} />
            <Route render={() => (<div>Miss</div>)} />
          </Switch>
        </>
      </ConnectedRouter>
    </Provider>
  </React.StrictMode>,
  document.getElementById('root')
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

Enter fullscreen mode Exit fullscreen mode

WE DID IT

navigate to localhost:3000/test to see our routing in action.

I am not going into detail about how to call the routes , since your setup will be probably different than mine.

Info on setting up linking and routing to pages:
https://github.com/supasate/connected-react-router/blob/master/FAQ.md#how-to-navigate-with-redux-action

The code for this repo can be found here:

I couldn't find any articles that clearly or simply explained this process , so i decided to publish this, feel free to flame me in the comments or offer suggestions on expanding this!

thanks so much.

Top comments (3)

Collapse
 
ilumin profile image
Teerasak Vichadee

I think you should use RTK.configureStore instead of redux.createStore

Collapse
 
aashiqincode profile image
Aashiq Ahmed M

why are we calling the store() instead of just passing , does it applied only to the redux toolkit or what?