> For the complete documentation index, see [llms.txt](https://fe-qasir.gitbook.io/qiblat-documentation/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://fe-qasir.gitbook.io/qiblat-documentation/integrations/redux-configs.md).

# Redux Configs

## How to use

Here we use the Redux variant family [Redux](https://redux.js.org/), [react-redux](https://react-redux.js.org/), [redux-thunk](https://github.com/reduxjs/redux-thunk), [redux-persist](https://github.com/rt2zz/redux-persist), [next-redux-wrapper](https://github.com/kirill-konshin/next-redux-wrapper) for handle all state managements system. The installation method is as follows below.

### Step 1: Set up STORE configs

Adding file & code in `./src/lib/redux/store.js`. This is configs supported for handle SSR state & CSR state.

```jsx
import { createStore, applyMiddleware } from 'redux';
import { createWrapper } from 'next-redux-wrapper';
import thunkMiddleware from 'redux-thunk';
import combinedReducer from './reducers';

// BINDING MIDDLEWARE
const bindMiddleware = (middleware) => {
  if (process.env.NODE_ENV !== 'production') {
    const { composeWithDevTools } = require('redux-devtools-extension');
    return composeWithDevTools(applyMiddleware(...middleware));
  }
  return applyMiddleware(...middleware);
};

const makeStore = ({ isServer }) => {
  if (isServer) {
    //If it's on server side, create a store
    return createStore(combinedReducer, bindMiddleware([thunkMiddleware]));
  } else {
    //If it's on client side, create a store which will persist
    const { persistStore, persistReducer } = require('redux-persist');
    const storage = require('redux-persist/lib/storage').default;

    const persistConfig = {
      key: process.env.NEXT_PUBLIC_APP_NAME ? process.env.NEXT_PUBLIC_APP_NAME : 'nextjs',
      whitelist: ['register', 'auth'], // only counter will be persisted, add other reducers if needed
      storage, // if needed, use a safer storage
    };

    const persistedReducer = persistReducer(persistConfig, combinedReducer); // Create a new reducer with our existing reducer

    const store = createStore(persistedReducer, bindMiddleware([thunkMiddleware])); // Creating the store again

    store.__persistor = persistStore(store); // This creates a persistor object & push that persisted object to .__persistor, so that we can avail the persistability feature

    return store;
  }
};

export const wrapper = createWrapper(makeStore);
```

### **Step 2: Set up reducers configs**

Adding file & code in `./src/lib/redux/reducers.js`.&#x20;

```jsx
import { combineReducers } from 'redux';

import count from 'store/example-redux/count/reducer';
import tick from 'store/example-redux/tick/reducer';

const combinedReducer = combineReducers({
  count,
  tick,
});

export default combinedReducer;
```

### **Step 3: Init actions & reducers**&#x20;

We have 2 examples related to using a reducer. Adding action & reducer in&#x20;

**First we make count reducer.** Adding file & code in `./src/store/example-redux/count/action.js` & `./src/store/example-redux/count/reducer.js`

**action.js**

```jsx
export const countActionTypes = {
  ADD: 'ADD',
};

export const addCount = () => (dispatch) => {
  return dispatch({ type: countActionTypes.ADD });
};
```

**reducer.js**

```jsx
import { countActionTypes } from './action';

const countInitialState = {
  count: 0,
};

export default function reducer(state = countInitialState, action) {
  switch (action.type) {
    case countActionTypes.ADD:
      return Object.assign({}, state, {
        count: state.count + 1,
      });
    default:
      return state;
  }
}
```

**Second we make tick reducer.** Adding file & code in `./src/store/example-redux/tick/action.js` & `./src/store/example-redux/tick/reducer.js`

**action.js**

```jsx
export const tickActionTypes = {
  TICK: 'TICK',
};

export const serverRenderClock = (isServer) => (dispatch) => {
  return dispatch({
    type: tickActionTypes.TICK,
    light: !isServer,
    ts: Date.now(),
  });
};

export const startClock = () => (dispatch) => {
  return setInterval(() => dispatch({ type: tickActionTypes.TICK, light: true, ts: Date.now() }), 1000);
};
```

**reducer.js**

```jsx
import { tickActionTypes } from './action';

const tickInitialState = {
  lastUpdate: 0,
  light: false,
};

export default function reducer(state = tickInitialState, action) {
  switch (action.type) {
    case tickActionTypes.TICK:
      return Object.assign({}, state, {
        lastUpdate: action.ts,
        light: !!action.light,
      });
    default:
      return state;
  }
}
```

### Step 4: Implement store wrapper&#x20;

Adding code in ./src/pages/\_app.js

```jsx
// Vendors
import { useStore } from 'react-redux';
import { PersistGate } from 'redux-persist/integration/react';

// Configs
import { wrapper } from '@/redux/store';

const App = (props) => {
    const store = useStore((state) => state);
    ...
    return (
        ...
        <PersistGate persistor={store.__persistor} loading={null}>
            ...
        </PersistGate>
        ...
    )
};

export default wrapper.withRedux(App);
```

### **Step 5: Implement in pages route Next.js**

**For test SSR mode**. Adding file & code in `./src/pages/example-redux/ssr.js`

```jsx
import { useEffect } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import Page from '@/hoc/example-redux/Page';
import { addCount } from 'store/example-redux/count/action';
import { wrapper } from '@/redux/store';
import { serverRenderClock, startClock } from 'store/example-redux/tick/action';

const Other = (props) => {
  useEffect(() => {
    const timer = props.startClock();

    return () => {
      clearInterval(timer);
    };
  }, [props]);

  return <Page title="Other Page" linkTo="ssg" />;
};

export const getServerSideProps = wrapper.getServerSideProps(async ({ store }) => {
  store.dispatch(serverRenderClock(true));
  store.dispatch(addCount());
});

const mapDispatchToProps = (dispatch) => {
  return {
    addCount: bindActionCreators(addCount, dispatch),
    startClock: bindActionCreators(startClock, dispatch),
  };
};

export default connect(null, mapDispatchToProps)(Other);
```

**For test CSR or SSG mode**. Adding file & code in `./src/pages/example-redux/ssg.js`

```jsx
import { useEffect } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import Page from '@/hoc/example-redux/Page';
import { addCount } from 'store/example-redux/count/action';
import { wrapper } from '@/redux/store';
import { serverRenderClock, startClock } from 'store/example-redux/tick/action';

const Index = (props) => {
  useEffect(() => {
    const timer = props.startClock();

    return () => {
      clearInterval(timer);
    };
  }, [props]);

  return <Page title="Index Page" linkTo="ssr" />;
};

export const getStaticProps = wrapper.getStaticProps(async ({ store }) => {
  store.dispatch(serverRenderClock(true));
  store.dispatch(addCount());
});

const mapDispatchToProps = (dispatch) => {
  return {
    addCount: bindActionCreators(addCount, dispatch),
    startClock: bindActionCreators(startClock, dispatch),
  };
};

export default connect(null, mapDispatchToProps)(Index);
```
