# 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);
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://fe-qasir.gitbook.io/qiblat-documentation/integrations/redux-configs.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
