cmy0 2019-12-29
在上篇文章中,基于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) ]) }
从上面可以看到我们将所有的操作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 }