阅读 771

Redux工作流及工程化编码指南

一、什么是Redux?

Redux 是 JavaScript 状态容器, 提供可预测化的状态管理。它专门为React.js这门框架设计,但并不是只能用于react,可以用于任何界面库。

那为什么React.js需要这个状态容器管理呢?

首先明确React是什么,根据官方的定义,React仅仅是一个视图层的框架,解决的是数据与模板的渲染问题,但是并没有提供数据的状态管理方案,这在大型项目中是一个非常大的痛点。比如说:

凡是复杂一些的应用都会有这样组件树的结构,那么非父子组件如何传递数据呢?比如标记上蓝色的组件与右下角的组件进行数据传递,如果仅仅用react组件的父子传值方法,那么需要先传递给父组件,然后由父组件传给上一级的父组件,然后再向下面的子组件传递......明明只是两个组件的交互,居然要 用如此复杂的操作,是不是让人非常沮丧呢?如果项目稍微复杂,即使可以开发,但也变得不可维护。因此Redux应运而生。让Redux统一管理数据,任何组件对数据的操作,都交给redux管理,这样就大大提高了开发和维护的效率。

二、Redux设计原则

1、单一数据源

使用redux的程序,所有的state都存储在一个单一的数据源store内部,类似一个巨大的对象树。

2、state只读

state是只读的,外部能改变state的唯一方式是通过触发action来修改

3、使用纯函数进行修改

为了描述action如何改变state,需要编写一些具体的逻辑,这些逻辑写在reducer中。而reducer就是一些纯函数。

纯函数:有固定的参数输入且有固定的return输出,不会存在异步的操作,同时在这个过程中不会修改参数的值。

三、Redux工作流

也许第一次看不是很明白,没有关系,可以用图书馆借书的例子做一个类比:

一图胜千言,其实redux的工作流程也是非常简单的。

四、使用redux

// src/store/index.js
import { createStore } from 'redux';
import reducer from './reducer';
//通过createStore创建一个store,把reducer作为参数传入
const store = createStore(
  reducer,
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()//chrome中激活redux devtools插件
);

export default store;
复制代码
// src/store/reduce.js
const defaultState = {
  inputValue: '',
  list: []
}
export default (state = defaultState, action) => {
  if(action.type === 'add_item') {
    const newState = JSON.parse(JSON.stringify(state))
    newState.list.push(newState.inputValue)
    newState.inputValue = ''
    return newState
  }
  return state;
}
复制代码
// App.js
import React, { Component } from 'react'
import store from './store/index.js'

class App extends Component {
  constructor(props) {
    super(props);
    //从redux拿到state
    this.state = store.getState()
    //store需要通过一个方法给组件传递newState,并将这个方法传入subscribe函数的参数里面
    this.handleStoreChange = this.handleStoreChange.bind(this)
    store.subscribe(this.handleStoreChange)
  }
  render() { 
    return ( 
     //渲染部分
    );
  }
  handleStoreChange() {
    //更新组件状态
    this.setState(store.getState())
  }
}

export default App;
复制代码
  //在响应点击事件的函数中
  handleItemClick(e) {
    const action = {
        type: 'add_item',
        value: e.target.value
    }
    //由store进行action的分发
    store.dispatch(action)
  }
复制代码

五、更科学地编写Action

仔细想想,其实上面编写响应函数里面的action部分其实是有问题,因为当我们输入字符串的时候,一不小心输错了一个字母,无法进行状态的变化,但这个时候reducer识别不了对应的type,也不会报错。这个时候可能调试会浪费非常多的时间。

这时候就需要编写更加规范的action来防止这种事故。

// src/store/actionTypes.js
export const ADD_ITEM = 'add_item'

// src/store/actionCreators.js
import { ADD_ITEM } from "./actionTypes";
export const getAddItemAction = (e) => ({
  type: ADD_ITEM
  value: e.target.value
})
// src/store/reducer.js
import { ADD_ITEM } from './actionTypes'

const defaultState = {
  inputValue: '',
  list: []
}
export default (state = defaultState, action) => {
  //这里改成ADD_ITEM
  if(action.type === ADD_ITEM) {
    const newState = JSON.parse(JSON.stringify(state))
    newState.list.push(newState.inputValue)
    newState.inputValue = ''
    return newState
  }
  return state;
}
复制代码

然后,在App.js中,

//首先引入Action
import { getAddItemAction } from './store/actionCreators'
//修改响应函数
handleItemClick(e) {
    const action = getAddItemAction(e)
    store.dispatch(action)
}
复制代码

这样的编写方式虽然引入了actionTypes和actionCreators,操作更加 麻烦,但是更能应对大型复杂项目的action管理,实际上提高了开发维护的效率。

这是对redux初步的小结,希望对大家有所帮助。

关注下面的标签,发现更多相似文章
评论