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.
Top comments (2)
I think you should use
RTK.configureStore
instead ofredux.createStore
why are we calling the store() instead of just passing , does it applied only to the redux toolkit or what?