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
}

参考

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

原文地址:https://www.cnblogs.com/fozero/p/12113937.html

时间: 2024-10-05 07:28:42

nextjs的开发使用(二)---引入redux状态管理的相关文章

Redux状态管理方法与实例

状态管理是目前构建单页应用中不可或缺的一环,也是值得花时间学习的知识点.React官方推荐我们使用Redux来管理我们的React应用,同时也提供了Redux的文档来供我们学习,中文版地址为http://cn.redux.js.org/index.html 前言 虽然官方文档上说只需几分钟就能上手 Redux,但是我个人认为即便你看个两三天也可能上手不了,因为文档里面的知识点不仅数量较多,而且还艰涩难懂,不结合一些实例来看很难用于实际项目中去. 但是不要担心自己学不会,这不我就给大家带来了这篇干

react+redux状态管理实现排序 合并多个reducer文件

这个demo只有一个reducer 所以合并reducer这个demo用不到 ,但是我写出来这样大家以后可以用到,很好用,管理多个reducer,因为只要用到redux就不会只有一个reducer所以这个合并reducer很好用. 需要的技术:react-redux    redux实现状态管理 装饰器:transform-decorators-legacy下载 第一步下载transform-decorators-legacy npm install transform-decorators-l

ASP.NET MVC5 网站开发实践(二) Member区域 - 添加文章

转自:http://www.cnblogs.com/mzwhj/p/3592895.html 上次把架构做好了,这次做添加文章.添加文章涉及附件的上传管理及富文本编辑器的使用,早添加文章时一并实现. 要点: 富文本编辑器采用KindEditor.功能很强大,国人开发,LGPL开源,自己人的好东西没有理由不支持. 附件的上传同样基于KindEditor实现,可以上传图片,flash,影音,文件等. 目录 ASP.NET MVC5 网站开发实践 - 概述 ASP.NET MVC5 网站开发实践(一)

iOS开发多线程篇—线程的状态

iOS开发多线程篇—线程的状态 一.简单介绍 线程的创建: self.thread=[[NSThread alloc]initWithTarget:self selector:@selector(test) object:nil]; 说明:创建线程有多种方式,这里不做过多的介绍. 线程的开启: [self.thread start]; 线程的运行和阻塞: (1)设置线程阻塞1,阻塞2秒 [NSThread sleepForTimeInterval:2.0]; (2)第二种设置线程阻塞2,以当前时

Titanium Module 模块开发(二)蓝牙控制 Module

今天 ,正好项目需要添加蓝牙的控制功能,我去Titianium 文档搜了一下,发现 只有Tizen 系统有,其他的都没有,只能自己做Module. 借这个机会,记录一下蓝牙控制Module 的开发过程中遇到的问题和一些知识点. 编写Module 建立项目 首先 ,建立一个Module 项目,不会的话参考:Titanium-Modules 模块开发 (一) :模块开发基础 创建完成后会是这样: 添加蓝牙相关方法 打开BluetoothadapterModule.java 文件 可看到如下代码: 2

PictureShare开发(二)地图Mark(标记)的处理(1)

问题一:采用哪种覆盖物 本来想用百度地图的图片覆盖物功能,图片覆盖物有一个很好的优点,就是图片的大小会随着MapView的ZoomLevel变化而变化,非常的方便,但是利用图片覆盖物的话有一个致命的缺点:就是很难获取到点击事件. 所以,我接下来想到用自定义View作为覆盖物.这样就可以很方便地获取触摸事件.可是问题又来了,自定义View的话效果很一般(移动地图的时候自定义View会出现严重的漂移,严重影响视觉效果) 最后,采用自定义图层的办法(ItemizdOverlay) 自定义图层的话,每次

学iOS开发(二)——实现一款App之编写自定义类

今天学iOS开发(二)--实现一款App之编写自定义类 当开发iOS应用程序时,你会发现在许多场景下,你需要编写自己的自定义类.当你需要数据和自定义行为一起打包时,自定义类就很有用了.在一个自定义的类中,你可以为存储.操纵和显示数据定义你自己的行为. 例如,考虑iOS Clock app中的全球时钟标签(World Clock tab).这个表视图中的单元格需要显示比标准表视图单元格更多的内容.这是一个不错的机会实现一个扩展UITableViewCell行为的子类,从而在给定的表视图单元格中显示

QT开发(二十四)——QT文件操作

QT开发(二十四)--QT文件操作 一.QT文件操作简介 QT中的IO操作通过统一的接口简化了文件与外部设备的操作方式,QT中文件被当作一种特殊的外部设备,文件操作与外部设备操作相同. 1.IO操作的主要函数接口 打开设备:bool open(OpenMode mode) 读取数据:QByteArray read(qint64 maxSize) 写入数据:qint64 write(const QByteArray & byteArray) 关闭设备:void close() IO操作的本质是连续

仿酷狗音乐播放器开发日志二十一 开发动态调色板控件(附源代码)

转载请说明原出处,谢谢~~ 上一篇仿酷狗日志结束后,整个换肤功能就仅仅剩下调色板功能没有做了.我本以为会非常easy.可是研究了酷狗的调色板功能后发现不是那么简单的事情.首先看一下酷狗的调色板的样子: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemh1aG9uZ3NodQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" > waterm