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?