Setting up Redux Toolkit and React Router
chowderhead
Posted on May 6, 2021
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;
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';
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
})
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
}
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
}
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'
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')
);
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();
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.
Posted on May 6, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 29, 2024
November 29, 2024