8

大型React项目redux配置方案

 3 years ago
source link: https://zhuanlan.zhihu.com/p/148534833
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

大型React项目redux配置方案

北京奇观技术有限责任公司 软件开发工程师

进入新公司,处理老项目状态管理问题,这里分步骤介绍我是如何为老项目搭配redux的。

1 使用到的包和方法

react-redux: Provider、connect

react-router-redux:syncHistoryWithStore、routerReducer

redux:applyMiddleware、createStore、combineReducers、bindActionCreators

redux-thunk:thunkMiddleware

1.1react-redux

API · Redux​www.redux.org.cn

<Provider store> :这个API是为了让每一个组件的conntect()方法都能获得Redux Store。

根组件只嵌套在<Provider> 中才能使用connect()方法。这个API包裹在最外层,在router外。

<Provider store={store}>
    <Router history={history}>
      <Route path="/" component={App}>
        <Route path="foo" component={Foo}/>
        <Route path="bar" component={Bar}/>
      </Route>
    </Router>
  </Provider>

connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options]):这个方法用于连接React组件和Redux store 连接操作对原组件没有任何影响。

mapStateToProps是为了监控redux store的变化 只要redux store发生了变化 函数就会被调用。

const mapStateToProps = (state) => ({
  state : state.serviceExamineReducer
}) 

mapDispatchToProps 这个方法是为了分离action,把aciton抽离出去专门建一个action.js 这样可以把逻辑和渲染分离开。

const mapDispatchToProps = (dispatch) => {
  return bindActionCreators(actions,dispatch)
}

整体写法 用connect包裹住这个要抛出的组件

export default  connect(mapStateToProps,mapDispatchToProps)(ServiceExamine)

1.2react-router-redux:syncHistoryWithStore、routerReducer

这两个api暂时不用。他俩的意义是本来react-router自己管理自己的状态(location、history、path等),现在用syncHistoryWithStore绑定react的store 用routerReducer绑定reducer ,帮状态全部交给redux来管理,我觉的没有必要可以去掉。

1.3redux

http://cn.redux.js.org//docs/api/index.html​cn.redux.js.org

applyMiddleware(...middlewares)

这个方法用于和createStore结合使用,正常来说我们的store = createStore(reducer),这个方法单独封装createStore。

import { createStore, applyMiddleware} from 'redux'
import thunkMiddleware from 'redux-thunk'

const createStoreWithMdware = applyMiddleware( 
            thunkMiddleware
        )(createStore);

export default createStoreWithMdware;

然后App.js修改

import createStoreWithMdware from './store/index';
store = createStoreWithMdare(reducer)

这个方法中间参数为无数个中间件,因为我们reducer为纯函数,但是我们可以放置多个中间件帮助我们去处理,比如thunkMiddleware 是一个异步处理中间件,本来我们的action只能时同步的,有了这个中间件我们可以像定义普通action一样定义异步的action

createStore(reducer, [preloadedState], [enhancer])

创建一个Redux store来存放应用的全部的state 这个一般使用就传入一个reducer就行,后面的参数没有用过

combineReducers(reducers)

这个是因为随着项目越来越庞大,一个reducer会变得越来越臃肿,使用这个方法可以把每个模块的reducer单独抽离出去,然后连接到一起。

import {combineReducers} from 'redux';
import articleReducer from '../containers/useless/article/reducer';
import imgsReducer from '../containers/useless/imgs/reducer';
import idManageReducer from '../containers/userInfo/idManage/reducer';


const rootReducer = combineReducers({
    articleReducer : articleReducer,
    imgsReducer : imgsReducer,
    idManageReducer : idManageReducer,
}) 
  
export default rootReducer

bindActionCreators(actionCreators, dispatch)

这个方法是为了重新封装action ,以便组件能直接调用action.js里的每一个方法,这个是组件是connect()方法里的一个参数。

import * as actions from './action';
import { bindActionCreators } from 'redux'; 
const mapDispatchToProps = (dispatch) => {
  return bindActionCreators(actions,dispatch)
}

action 就是我们定义的全部触发方法

1.4 redux-thunk

thunkMiddleware

这个是一个中间件 帮助我们处理异步的action 上面的方法介绍的有

const createStoreWithMdware = applyMiddleware( 
            thunkMiddleware
)(createStore);

2 具体实现

1 新建一个reducer文件夹

index.js

import {combineReducers} from 'redux';

/**
 * zyx
 * 2020/6/6
 * 将reducer拆分成多个不同的reducer 防止后期项目越来越大reducer变得越来越臃肿
 * 最好是一个模块建一个单独得reducer
 */
const rootReducer = combineReducers({
    //在这里导入每个模块的reducer
}) 
  
export default rootReducer

2 新建一个store文件夹

index.js

import { createStore, applyMiddleware} from 'redux'
import thunkMiddleware from 'redux-thunk'

/**
 * zyx
 * 2020/6/6
 * 通过createStoreWithMdwareAPI创建createStore
 * 1 包裹一个createStore方法 2 包裹扩展redux的中间件
 * thunkMiddleware中间件为了让reduc支持处理异步的action
 */
const createStoreWithMdware = applyMiddleware( 
            thunkMiddleware
        )(createStore);

export default createStoreWithMdware;

3 修改 App.js

import React, { Component } from "react";
import './App.css';
//配置hashRouter 使用独立的router文件
import { createHashHistory } from 'history';
import { HashRouter as Router } from 'react-router-dom';
import { renderRoutes } from 'react-router-config';
//引入配置的routes
import Routes from './routes';

//创建路由history
const history = createHashHistory();

class App extends Component {
  render() {
    return (
      <div>
          <Router history={history}>
            {renderRoutes(Routes)}
          </Router>
      </div>
    );
  }
}
export default App;
import React, { Component } from "react";
import './App.css';
//配置hashRouter 使用独立的router文件
import { createHashHistory } from 'history';
import { HashRouter as Router } from 'react-router-dom';
import { renderRoutes } from 'react-router-config';
//引入配置的routes
import Routes from './routes';
//配置redux
import { Provider } from 'react-redux';
import createStoreWithMdware from './store/index';
import reducers from './reducers/index'; 

//创建store
const store = createStoreWithMdware(reducers);  
//创建路由history
const history = createHashHistory();

class App extends Component {
  render() {
    return (
      <div>
        <Provider store={store}> 
          <Router history={history}>
            {renderRoutes(Routes)}
          </Router>
        </Provider>
      </div>
    );
  }
}
export default App;

这时候我们已经把redux配入了项目中,可以开始对具体的模块进行状态管理了

4 对具体的模块进行状态管理

在一个模块中新建action.js 和 reducer.js

action.js 是为了把模块中的全部逻辑和数据处理抽离出来,index.js专注于渲染页面

reducer.js 定义该模块的reducer

这里我们把一个弹窗的状态抽离出来通过redux进行管理

原本项目中这个弹窗的状态通过 this.state.modalShow来管理

this.state = {
      modalShow: false,//注册成功提示是否展示
};

//控制弹窗的关闭弹出 type:true/false
 modalShowOnchange=(type)=> {
    this.setState({
      modalShow: type,
    });
}

reducer.js

import {MODAL_SHOW} from './action';

function diversionReducer(state={
    modalShow:false,//弹窗是否弹出
},action){
    switch (action.type){
        //修改弹窗状态
        case MODAL_SHOW:
            return {
                modalShow:action.data.modalShow,
            }
        default:
            return state;
    }
}

export default diversionReducer;

action.js

export const MODAL_SHOW = 'MODAL_SHOW';
/**
 * Author : zyx
 * date : 2020/6/6
 * 控制弹窗是否出现
 */
  export function modalStateChange(state) {   
    let tempObj = {
        modalShow:state
    }
    return (dispatch) => {
        dispatch({
            type : MODAL_SHOW,
            data : tempObj  
        })
    }
  }  

index.js内的修改内容

//引入redux
import { bindActionCreators } from 'redux';
import {connect} from 'react-redux'
import * as actions from './action' 

// this.state = {
//   modalShow: false,//注册成功提示是否展示
// };

 modalShowOnchange=(type)=> {
    //调用定义的action
    this.props.modalStateChange(type)
}

//连接store、reducer、action
const mapStateToProps = (state) => ({
  state : state.diversionReducer
})
const mapDispatchToProps = (dispatch) => {
  return bindActionCreators(actions,dispatch)
}

export default  connect(mapStateToProps,mapDispatchToProps)(diversion)

这样就完成了对弹窗状态的管理

这里只做这一个简单的示例,具体项目的很多状态都可以抽离出去放在action.js里,比如数据请求了、分页数据渲染了,同时也可以直接把处理数据的方法也都封装在action.js里。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK