nextjs的开发使用---引入redux状态管理

Posted fozero

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了nextjs的开发使用---引入redux状态管理相关的知识,希望对你有一定的参考价值。

在上篇文章中,基于react的nextjs服务端渲染框架学习使用
学习了解了一些关于nextjs的东西,并做了一个小demo,这篇文章将对上篇文章做一个补充,在nextjs中引入redux

安装

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

创建目录及文件

创建redux文件夹,并在下面创建index.js,actions,reducers,rootSaga.js文件

1、redux/index.js

初始化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

定义一些action常量

// 推荐
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
获取action传过来的数据存储到state中

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结构改造

从上面可以看到我们将所有的操作actions、reducers和saga中,如果项目越来越大,就会变得难以维护。下面我们按照不同的功能分别创建不同的actions、reducers和sage文件
目录结构如下:

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

1、saga/index.js
这里主要是监听action动作,触发对应的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
在saga中发起接口请求,并将结果数据通知action保存在state中

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
所有的actions动作在这里统一创建

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
接收到action发起的动作之后,将数据保存在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
接着,我们将所有的saga方法导入进来,并通过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
最后在index.js中,导入所有的rootSaga和reducer,使用 applyMiddleware 将 middleware 连接至 Store

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
}

参考

以上是关于nextjs的开发使用---引入redux状态管理的主要内容,如果未能解决你的问题,请参考以下文章

NextJS:我是不是需要使用 getInitialProps 和 next-redux-wrapper 来向所有页面共享状态?

Redux 商店使用 nextJS 自行重置路由更改

使用带有 NextJS 的 Redux 开发工具:当 Redux 被称为服务器端时,如何找出存储中发生的事情?

如何将 Redux devtools 与 Nextjs 一起使用?

react状态管理器

浅谈redux-form在项目中的运用