本篇将介绍redux跟react-redux。这里打算是介绍这两个插件在react项目中的运用。redux是可以在其他库中使用的。
前面使用react开发项目,是可以实现大部分需求的。但是react毕竟是一个实现视图层的框架,它在数据层的实现还是存在一些不足的。比如当项目较大,需要使用大量的数据,父子组件之间的数据通信特别频繁的时候,性能就会直线下滑;当数据发生改变的时候,就无从得知数据是从哪里发生改变的。
redux作为一个应用数据流框架,它的最大的特点就是应用状态的管理,它用一个单独的常量状态树store
保存整个应用的状态。这个状态树不能直接被改变。
我们分析一下。如果没有redux,react组件的所有状态state
将各自存储于组件中,一旦遇到不同父组件的组件之间的通信问题,需要把数据先传到能使两个组件通信的上层组件,然后在下发到另一个组件。而如果使用redux,则数据都存储在常量状态树store
中,所有组件获取状态数据都从store
中直接获取。而组件需要修改状态数据时,只需要直接修改store
中的数据,其他组件就会获知store
的变化并自动重新获取状态。这样可以减少组件之间大规模的通讯消耗。
redux工作流程
我们了解了react的组件components
跟redux的常量状态树store
,那他们是怎么串连起来,是怎么样的工作流程呢?
这里需要考虑三个场景,一个是components
需要修改store
中的数据,一个是store
中实现数据的更新,还有一个就是store
的数据更新之后新状态同步到components
中。
最主要是前两个场景。这里需要引入redux中两个概念。
actionCreator
因为常量状态树store
的状态数据不允许直接修改,所以当components
需要修改store
中的数据时,需要通过actionCreator
中的action去让store
做数据的更新。
actionCreator
是一个action的集合,这个集合中包含了各种用于申请修改的action
。这个action
需要包括修改数据的类型跟需要修改的数据。在components
发出store.dispatch(action)
之后提交给store
,完成修改申请。
reducer
当store
得到action时,它本身没有什么方法可以修改数据,所以需要用到reducer
来实现状态的更新。store
会把当前的state
跟前面接收到的action传给reducer
,reducer
会根据传入的action类型进行状态更新,然后再返回新的state
。
组件的状态更新
关于最后store
的数据更新之后新状态同步到components
中,阮一峰的《Redux 入门教程(一):基本用法》中有提到,当store
中state
发生变化后,store
会调用监听函数,监听函数就可以更新组件中的state
,组件就可以重新渲染页面。
react-redux实战
安装react-redux
在react项目中,引入react-redux还需要引入redux:
1 | npm install redux --save |
这样在react项目中才可以使用react-redux。
创建store
先在项目中创建一个store的文件夹,然后在创建一个index.js的js文件。在这个js文件中写下以下代码:
1 | import { createStore } from 'redux'; |
首先,先从redux中引入createStore
,然后通过createStore
来创建一个store
,最后导出。
创建reducer
上面我们已经完成store
的创建,然后需要创建reducer
来给store
处理数据。在store目录下创建一个reducer.js的js文件。redux中,reducer
其实是一个函数,所需要引入的参数为当前的state(preState)
跟action
,而返回的是一个修改后的state(newState)
。一般初始化的时候,没有当前的state(preState)
,所以会先声明一个defaultState
:
1 | const defaultState = { |
上面的代码中,先声明一个defaultState
作为state
的初始化状态,然后导出一个函数,这个函数中通过判断action.type
来修改获得newState
,然后返回出去。
创建之后,需要把reducer
传入到store
中,因此上面的index.js需要稍加修改:
1 | import { createStore } from 'redux'; |
创建actionCreator
actionCreator
还是要强调,它是一个方法的是一个action的集合,这个集合中包含了各种用于申请修改的action
。当然,把所有action都只在需要的时候再编写也可以,但是把所有action集中起来可以提高代码的可读性,可维护性。每一个action方法最终都是返回一个对象,这个对象包含有修改类型type跟需要修改的值。在reducer.js中,大家可以看到传入的action.type是会在switch语句中作为判断值,然后修改值则会在判断后做对应的修改。
在store目录下创建一个actionCreator.js的js文件,然后写入所有需要导出的action方法:
1 | export const action1 = (value1) => ({ |
在reducer中,action.type作为判断时,会再写一次。为了保证不出抄写错误,方便后期排查bug,一般还可以把actionType集中起来:
1 | export const actionType1 = 'action_type_1'; |
那么,在actionCreator中就可以改写成:
1 | import * as constants from './actionType'; |
组件中的使用
组件中使用一般分引入store,调用action申请及store修改订阅。
组件中会现在构造函数中引入store:
1 | constructor (props) { |
当状态需要修改时,通过store.dispatch()
调用action:
1 | store.dispatch(actionCreators.action1(value1)); |
action方法返回对象将交给store,但是store不会处理,而是通过dispatch方法交给reducer处理。reducer接收到action后,会根据修改类型type对数据进行更新。在store的状态进行更新之后组件就需要更新。但是组件的状态更新还需要做一步操作,就是对store变化的订阅。这个订阅也是在constructor()
完成:
1 | constructor(props) { |
以上就是对redux跟react-redux使用的总结。