nextjs use development (b) --- the introduction of state management redux

In the last article, based on server-side rendering nextjs react framework of learning to use the
study to understand something about nextjs and made a small demo, this article will make the article a supplement, introduced in nextjs the redux

installation

// 安装redux相关依赖
yarn add redux redux-saga react-redux
// 安装next.js对于redux的封装依赖包
yarn add next-redux-wrapper next-redux-saga
yarn add redux react-redux

Create a directory and file

Create a redux folder and create index.js below, actions, reducers, rootSaga.js file

1、redux/index.js

Initialization store

import { createStore, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';
import rootSaga from './rootSaga';
import rootReducer from './reducers';

export function initializeStore(initialState){
  // 创建一个 Saga middleware
  const sagaMiddleware = createSagaMiddleware();

  // 使用 applyMiddleware 将 middleware 连接至 Store
  const store = createStore(
    rootReducer,
    initialState,
    applyMiddleware(sagaMiddleware)
  );

  // 运行并监控各个action
  store.sagaTask = sagaMiddleware.run(rootSaga);

  return store
}

2、redux/action-types.js

Define some action constants

// 推荐
export const GET_RECOMMEND_LIST = "GET_RECOMMEND_LIST";
// 获取App详情
export const GET_APP_INFO = "GET_APP_INFO";

3、redux/actions.js

import { createActions } from 'redux-actions'

// 使用createActions创建多个动作
export const {
  getAppInfoRequest,
  getAppInfoSucceed,
  addAppInfoRequest,
  getPostsSucceed
} = createActions({
  GET_APP_INFO_REQUEST: id => {
    return id
  },
  GET_POSTS_SUCCEED: res => {
    return res
  },
  GET_APP_INFO_SUCCEED: res => {
    return res
  },
  ADD_APP_INFO_REQUEST: data => {
    return data
  }
})

4, redux / reducers.js
Get action pass over into state data storage

import { handleActions } from "redux-actions";
import * as types from "./action-types";

// 默认state
let defaultState = {
  searchList: [] //搜索结果列表
};

// 使用handleActions处理多个actions ,这里通过action.payload获取传过来的数据
const reducerCreators = handleActions(
  {
    [types.GET_APP_INFO_SUCCEED]: (state, action) => {
      return {
        ...state,
        appInfo: action.payload
      };
    },
    [types.GET_RECOMMEND_LIST_SUCCEEDED]: (state, action) => {
      return {
        ...state,
        recommendList: action.payload
      };
    }
  },
  defaultState
);

export default reducerCreators;

5、redux/rootSaga.js

import { put, call, takeLatest, all } from 'redux-saga/effects'
import {
  getAppInfoRequest,
  getAppInfoSucceed,
  addAppInfoRequest,
  getPostsSucceed
} from './actions'
import $api from '../api/index.js'
import * as fetchApi from '../utils/fetcher'

/**
 *
 * 获取app详情数据
 * @param {*} action
 */
export function* getAppInfo(action) {
  try {
    const posts = yield call(fetchApi.getPosts)
    yield put(getPostsSucceed(posts))
  } catch (error) {
    console.log(error)
  }
}

export function* addAppInfo(action) {
  console.log('action', action)
  console.log('addAppInfo process.browser', process.browser)
}

// 同时启动多个Sagas  监听action动作
export default function* rootSaga() {
  yield all([
    // takeLatest(actionCreators.appSearch, appSearch),
    takeLatest(addAppInfoRequest, addAppInfo),
    takeLatest(getAppInfoRequest, getAppInfo)
  ])
}

redux structural transformation

From the above we can see that all the operating actions, reducers and saga, if the project is growing, it will become difficult to maintain. Here we are created in accordance with the different functions of different actions, reducers and sage file
directory structure is as follows:

redux
|----app
    |-----saga
        |---index.js
        |---appSaga.js
    |-----actions.js
    |-----reducers.js
    |-----selectors.js
|----project
index.js
rootSaga.js

1, saga / index.js
this action is to monitor the operation of the main trigger corresponding method saga

import { takeLatest, all } from 'redux-saga/effects'
import { getAppInfoRequest, addAppInfoRequest } from '../actions'

import { addAppInfoSaga, getAppInfoSaga } from './appSaga'

// 同时启动多个Sagas  监听action动作
export function* appWatcher() {
  yield all([
    takeLatest(addAppInfoRequest, addAppInfoSaga),
    takeLatest(getAppInfoRequest, getAppInfoSaga)
  ])
}

2, saga / appSaga.js
initiation request saga interfaces, and the resulting data stored in the action state of the notification

import * as fetchApi from '../../../utils/fetcher'
import { put, call } from 'redux-saga/effects'
import { getPostsSucceed } from '../actions'
/**
 *
 * 获取app详情数据
 * @param {*} action
 */
export function* getAppInfoSaga(action) {
  // 通过action.payload获取数据

  try {
    const posts = yield call(fetchApi.getPosts)
    yield put(getPostsSucceed(posts))
  } catch (error) {
    console.log(error)
  }
}

export function* addAppInfoSaga(action) {
  console.log('action', action)
  console.log('addAppInfo process.browser', process.browser)
}

3, app / actions.js
all actions to create a unified actions here

import { createActions } from 'redux-actions'

// 使用createActions创建多个动作
export const {
  getAppInfoRequest,
  getAppInfoSucceed,
  addAppInfoRequest,
  getPostsSucceed
} = createActions({
  GET_APP_INFO_REQUEST: id => {
    return id
  },
  GET_POSTS_SUCCEED: res => {
    return res
  },
  GET_APP_INFO_SUCCEED: res => {
    return res
  },
  ADD_APP_INFO_REQUEST: data => {
    return data
  }
})

4, app / reducers.js
After receiving the action initiated operation, the data stored in the state

import { handleActions } from 'redux-actions'

import { getAppInfoSucceed, getPostsSucceed } from './actions'

// 默认state
let defaultState = {
  searchList: [] // 搜索结果列表
}

// 使用handleActions处理多个actions ,这里通过action.payload获取传过来的数据
const appReducer = handleActions(
  {
    [getAppInfoSucceed]: (state, action) => {
      return {
        ...state,
        appInfo: action.payload
      }
    },
    [getPostsSucceed]: (state, action) => {
      return {
        ...state,
        pageConfig: {
          page: action.payload.page,
          pageSize: action.payload.pageSize
        },
        listCollection: {
          posts: action.payload.list
        }
      }
    }
  },
  defaultState
)

export default appReducer

5, redux / rootSaga.js
Next, we will come all the way to import saga, and by combining methods combineSagas

import { combineSagas } from '../utils/sagaUtils'
import { appWatcher } from './app/saga'

export const rootSaga = combineSagas([appWatcher])



这里的sagaUtils是一个工具函数,使用map遍历fork所有的sagas
import { all, fork } from 'redux-saga/effects'

export const combineSagas = sagas =>
  function* rootSaga(args) {
    try {
      yield all(sagas.map(saga => fork(saga, args)))
    } catch (err) {
      console.error(err)
    }
  }

6, redux / index.js
Finally index.js in rootSaga and import all the reducer, connected to the middleware using the Store applyMiddleware

import { createStore, applyMiddleware, combineReducers } from 'redux'
import createSagaMiddleware from 'redux-saga'
import { rootSaga } from './rootSaga'
// import rootReducer from './reducers'

import appReducer from './app/reducers'

const rootReducer = combineReducers({
  appState: appReducer
})

export function initializeStore(initialState) {
  // 创建一个 Saga middleware
  const sagaMiddleware = createSagaMiddleware()

  // 使用 applyMiddleware 将 middleware 连接至 Store
  const store = createStore(
    rootReducer,
    initialState,
    applyMiddleware(sagaMiddleware)
  )

  // 运行并监控各个action
  store.sagaTask = sagaMiddleware.run(rootSaga)

  return store
}

reference

  • https://www.npmjs.com/package/next-redux-saga
  • https://www.codercto.com/a/31234.html
  • https://github.com/shaotianyu/blog-front

Guess you like

Origin www.cnblogs.com/fozero/p/12113937.html