Redux Setup in Your React Project - Personal Preference

The first thing is to install libraries for redux, as you may guess:

1npm install -S redux react-redux redux-logger reselect redux-persist

redux-logger is a redux middleware which is really really helpful in development, but it's up to you whether to use it or not.
reselect is a memoization implementation for redux.
redux-persist is for leveraging localStorage/sessionStorage browser APIs in redux.

Assuming that you have the react project structured in your own way, I'd create a new folder named redux inside the src/app folder:

1mkdir -p src/app/redux

For demonstration purposes, we gonna setup user reducer, which is specific to user domain.
Create a root reducer and store first, though.

1# inside the 'redux' folder:
2touch root-reducer.js store.js

Then create user reducer-related files:

1# inside the 'redux' folder:
2mkdir -p user
3cd user
4touch user.reducer.js user.types.js user.actions.js user.selectors.js

Overwhelming already? Nah~ it's not, let me explain what the files do.

user.reducer.js is a file that contains real reducer, which can be called CPU of redux.
user.types.js will be containing action types as variables(I'd call it mapping), which is a good convention in redux world.
user.actions.js has real action definitions in it.
user.selectors.js is for memoization which is a great concept for pure functions, and it's all about performance.

Here is our root-reducer.js file:

 1import { combineReducers } from 'redux';
 2import { persistReducer } from 'redux-persist';
 3import storage from 'redux-persist/lib/storage';
 4
 5import userReducer from './user/user.reducer';
 6import cartReducer from './cart/cart.reducer'; // just ignore this, it's only for demonstration of redux-persist setup
 7
 8const persistConfig = {
 9  key: 'root',
10  storage,
11  whitelist: ['cart']
12};
13
14const rootReducer = combineReducers({
15  user: userReducer,
16  cart: cartReducer,
17});
18
19export default persistReducer(persistConfig, rootReducer);

Here is our store.js file then:

 1import { createStore, applyMiddleware } from 'redux';
 2import { persistStore } from 'redux-persist';
 3import logger from 'redux-logger';
 4
 5import rootReducer from './root-reducer';
 6
 7const middlewares = [];
 8
 9if (process.env.NODE_ENV === 'development') {
10  middlewares.push(logger);
11}
12
13const store = createStore(rootReducer, applyMiddleware(...middlewares));
14
15const persistor = persistStore(store);
16
17export { store, persistor };

user.types.js file:

1export const UserActionTypes = {
2  SET_CURRENT_USER: 'SET_CURRENT_USER'
3}

user.reducer.js file:

 1import { UserActionTypes } from './user.types';
 2
 3const INITIAL_STATE = {
 4  currentUser: null
 5}
 6
 7const userReducer = (state=INITIAL_STATE, action) => {
 8  switch (action.type) {
 9    case UserActionTypes.SET_CURRENT_USER:
10      return {
11        ...state,
12        currentUser: action.payload
13      }
14    default:
15      return state;
16  }
17}
18
19export default userReducer;

user.actions.js file:

1import { UserActionTypes } from './user.types';
2
3export const setCurrentUser = user => ({
4  type: UserActionTypes.SET_CURRENT_USER,
5  payload: user
6})

user.selectors.js file:

1import { createSelector } from 'reselect';
2
3const selectUser = state => state.user;
4
5export const selectCurrentUser = createSelector(
6  [selectUser],
7  (user) => user.currentUser
8)

Phew ~ it's time to set it up in our index.js file:

 1import React from 'react';
 2import ReactDOM from 'react-dom';
 3import { BrowserRouter } from 'react-router-dom';
 4import { Provider } from 'react-redux';
 5import { PersistGate } from 'redux-persist/integration/react';
 6
 7import './index.scss';
 8import App from './App';
 9import { store, persistor } from './redux/store';
10
11ReactDOM.render(
12  <React.StrictMode>
13    <Provider store={store}>
14      <BrowserRouter>
15        <PersistGate persistor={persistor}>
16          <App />
17        </PersistGate>
18      </BrowserRouter>
19    </Provider>
20  </React.StrictMode>,
21  document.getElementById('root')
22);

Let's use our redux store in any component of our application finally:

 1import React from 'react';
 2import { connect } from 'react-redux';
 3import { createStructuredSelector } from 'reselect';
 4
 5import { setCurrentUser } from './redux/user/user.actions';
 6import { selectCurrentUser } from './redux/user/user.selectors';
 7
 8const YourComponent = props => {
 9  const { currentUser, setCurrentUser } = props;
10
11  //Do something fantastic with the state and the dispatch!
12
13  return (
14    <div />
15  );
16}
17
18const mapStateToProps = createStructuredSelector({
19  currentUser: selectCurrentUser
20});
21
22const mapDispatchToProps = dispatch => ({
23  setCurrentUser: user => dispatch(setCurrentUser(user))
24});
25
26export default connect(mapStateToProps, mapDispatchToProps)(YourComponent);

That's it. Once you setup the redux, it's pretty much repetitive task to use it in any corner of your application.
Happy coding! 😎

comments powered by Disqus