React+Redux-Saga+Seamless-Immutable+Reduxsauce后台系统搭建之路(二)

如何搭建

安装

首先我们先执行这条语句来安装我们需要的插件:

npm i redux react-redux redux-saga reduxsauce seamless-immutable --save

Redux DevTools

具体的安装方法在这里

文件目录

root
├── App.js
├── config.js
├── index.jsx
├── reducers
│   ├── detail.js
│   ├── home.js
│   └── index.js
└── saga
    ├── detail.js
    ├── home.js
    └── index.js

Redux+saga

/*
 * 入口文件index.jsx
 */
import React from 'react'
import { render } from 'react-dom'
import { HashRouter as Router, withRouter } from 'react-router-dom'
import App from './App'
import { createStore, applyMiddleware, compose } from 'redux'
import createSagaMiddleware from 'redux-saga'
import reducer from './reducers'
import rootSaga from './sagas'
import { Provider } from 'react-redux'

// 如果要使用redux devtools,必须添加这句代码
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
const sagaMiddleware = createSagaMiddleware()
const store = createStore(
  reducer,
  composeEnhancers(applyMiddleware(sagaMiddleware))
)
sagaMiddleware.run(rootSaga)

const AppWithRouter = withRouter(App) // withRouter 的作用是将history,location,match 三个对象传给子组件
render(
  
    
      
    
  ,
  document.getElementById('app')
)

Reducers

为了便于管理,我们将所有的reducers用combineReducers来合并:

/*
 * reducers/index.js
 */
import { combineReducers } from 'redux'
import detail from './detail'
import home from './home'

const rootReducer = combineReducers({
  detail,
  home
})

export default rootReducer

每一个reducer的具体实现是这样的(举例),同时也给出了reduxsauce的用法,此处用于生成ActionTypes和reducers,其实这里已经给出了一种better practice,reducer只负责修改数据,而不负责具体业务,所以只需要提供几个增删改的功能就可以了:

import Immutable from 'seamless-immutable'
import {
  Types as ReduxSauceTypes,
  createReducer,
  createTypes
} from 'reduxsauce'

export const types = createTypes(
  `
  MERGE_DATA
  SET_IN
  REMOVE
  RESET
`,
  { prefix: 'DETAIL_' }
)

const INITIAL_STATE = Immutable({
  supplierID: null,
  recruitID: null,
  userType: null, // supplier(供应商), shop(商户)
  data: {},
  list: {},
  step: 0,
  mode: 'common', // modify, common
  tabs: {
    defaultActiveKey: 'info',
    activeKey: 'info'
  },
  transfer: {
    targets: {}
  },
  modal: {
    type: '',
    title: '',
    visible: false
  }
})
export const mergeData = (state = INITIAL_STATE, action) => {
  const { payload } = action
  return state.setIn(['data', payload.status], payload.data)
}

export const setIn = (state = INITIAL_STATE, action) => {
  const { payload } = action
  const { path, value } = payload
  return state.setIn(path, value)
}

export const remove = (state = INITIAL_STATE, action) => {
  const { payload } = action
  const { path, status } = payload
  const prev = state.getIn(path)
  let next = prev
  if (Array.isArray(prev)) {
    let arr = prev.asMutable()
    arr.splice(status, 1)
    next = arr
  } else {
    next = prev.without(status)
  }
  return state.setIn(path, next)
}

export const reset = (state = INITIAL_STATE, action) => {
  return INITIAL_STATE.set('supplierID', state.supplierID)
    .set('recruitID', state.recruitID)
    .set('userType', state.userType)
}

export const HANDLERS = {
  [ReduxSauceTypes.DEFAULT]: defaultHandler,
  [types.MERGE_DATA]: mergeData,
  [types.SET_IN]: setIn,
  [types.REMOVE]: remove,
  [types.RESET]: reset
}

export default createReducer(INITIAL_STATE, HANDLERS)

saga

其实index.jsx接受的saga是一个generator函数,这个generator函数,最原生的写法是:

import { delay } from 'redux-saga'
import { call, put, takeEvery } from 'redux-saga/effects'

export function* helloSaga() {
  console.log('Hello Saga!')
}

export function* incrementAsync() {
  yield call(delay, 1000)
  yield put({ type: 'INCREMENT' })
}

export function* watchIncrementAsync() {
  yield takeEvery('INCREMENT_ASYNC', incrementAsync)
}

// single entry point to start all Sagas at once
export default function* rootSaga() {
  yield [helloSaga(), watchIncrementAsync()]
}

我这里做了一下变形,也就是把几个文件的saga合并起来:

import detailSaga from './detail'
import * as homeSaga from './home'

const genRoot = sagas => {
  let sagaArr = []
  Object.keys(sagas).forEach(sagasKey => {
    let item = sagas[sagasKey]
    Object.keys(item).forEach(key => {
      sagaArr.push(item[key]())
    })
  })
  return sagaArr
}

export default function * rootSaga () {
  yield genRoot({ detailSaga, homeSaga })
}

至此,项目的搭建方法大概就是这样,但是仅仅是会用还是不够的,刚开始使用这些工具的时候,我也踩了很多坑,徒增了很多代码量,后来经过优化以后,减少了很多代码,下面是我优化的过程。

你可能感兴趣的:(React+Redux-Saga+Seamless-Immutable+Reduxsauce后台系统搭建之路(二))