本文将解答以下的问题并搭建一个基于redux的react-native项目目录:
- Redux
- Redux和Flux对比有什么不同,为什么使用Redux
- Redux由哪几个部分构成
- 什么是异步action?如何处理异步的数据流?
Redux是JS的状态环境,提供了可预测化的状态管理,可以构建一致化的应用,运行于不同环境并且易于测试
Redux工作流程:”
- 用户操作View发出Action,发出的方式就到了dispatch方法;
- 然后Store自动调用Reducer,并且传入两个参数(当前的State和收到的Action),Reducer会返回新的State,如果有Middleware,Store会将当前的State和收到的Action传递给Middleware,Middleware会调用Reducer然后返回新的State;
- State一旦发生变化,Store就会调用监听函数来更新View
这就是一次的用户交互流程,整个数据流是单向流动的。
Redux和Flux的对比:
Redux秉承了Flux的单向数据流,Store是唯一数据源的思想
- Redux中没有Dispatcher:它使用Store的Store.dispatch()方法来把action传给Store,由于所有的action处理都会经过这个Store.dispatch()方法,所以在Redux中很容易实现Middleware机制。Middleware可以让你在reducer执行前与执行后进行拦截并插入代码,来达到操作action和Store的目的,这样一来就很容易实现灵活的日志打印、错误收集、API请求、路由等操作。
- Redux只有一个Store:Flux中允许有多个Store,但是Redux中只允许有一个,相较于多个Store的Flux,一个Store更加清晰,并易于管理;
Redux和Flux的最大不同是Redux没有 Dispatcher 且不支持多个 store。Redux只有一个单一的 store 和一个根级的 reduce 函数(reducer),随着应用不断变大,我们需要将根级的 reducer 拆成多个小的 reducers,分别独立地操作 state 树的不同部分,而不是添加新的 stores。
Redux三个基本原则
- 单一数据源:整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中;
- State 是只读的:唯一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象;
- 使用纯函数来执行修改:为了描述 action 如何改变 state tree ,你需要编写 reducers;
Redux的构成
- action:action就是一个描述发生什么的对象;
- reducer:形式为 (state, action) => state 的纯函数,功能是根据action 修改state 将其转变成下一个 state;
- store:用于存储state,你可以把它看成一个容器,整个应用只能有一个store。
Redux应用中所有的 state 都以一个对象树的形式储存在一个单一的 store 中。 惟一改变 state 的办法是触发 action,action就是一个描述发生什么的对象。 为了描述 action 如何改变 state 树,你需要编写 reducers。
集成方法:
首先先安装
1 2 3 |
yarn add redux yarn add react-redux yarn add redux-thunk |
第一步创建一个reducer,这个是中的reducer,因为一个应用有很多个子的reducer,所以在reducer创建的时候
1 2 3 4 5 6 7 8 9 10 11 12 |
import {combineReducers} from 'redux'; import theme from './theme'; /** * 3.合并reducer * @type {Reducer<CombinedState<{}>>} */ const index = combineReducers({ theme: theme, }); export default index; |
下面是一个子的reducer:
1 2 3 4 5 6 |
const defaultState = { theme: 'blue', }; export default function onAction(state = defaultState) { return state; } |
第二步创建一个store并引入中间件,store的引入方式比较的固定:
1 2 3 4 5 6 7 8 9 10 11 12 |
import {applyMiddleware, createStore} from 'redux'; import thunk from 'redux-thunk'; import reducers from '../reducer' const middlewares = [ thunk, ]; /** * 创建store */ export default createStore(reducers, applyMiddleware(...middlewares)); |
第三步将store传递给APP框架
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import React, {Component} from 'react'; import {Provider} from 'react-redux'; import AppNavigator from './navigator/AppNavigator'; import store from './store' export default class App extends Component{ render(){ /** * 将store传递给APP框架 */ return <Provider store={store}> <AppNavigator/> </Provider>; } } |
最后将启动文件更换成上面这个文件就好了
使用
下面实现的功能是实现点击按钮切换主题的功能,主要体现redux的部分:
首先建立了一个action
1 2 3 4 5 6 7 |
import Types from '../types'; export function onThemeChange(theme) { return { type: Types.THEME_CHANGE, theme:theme, }; } |
然后交给一个总的action:
1 2 3 4 5 |
import {onThemeChange} from './theme'; export default { onThemeChange, } |
action还有一个type:
1 2 3 4 |
export default { THEME_CHANGE:'THEME_CHANGE', THEME_INIT:'THEME_INIT', }; |
接下来在reducer里面根据action的类型来返回不同的state
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import Types from '../../action/types'; const defaultState = { theme: 'red', }; // 注意在reducer里面不能修改原来state,只能返回一个新的state export default function onAction(state = defaultState, action) { switch (action.type) { case Types.THEME_CHANGE: return { ...state, theme: action.theme, }; default: return state; } } |
然后在一个具体的页面就可以使用了,通过mapDispatchToProps将其注入到当前页面的props里面,在我们需要使用数据的时候取出来应用到界面里面来,然后在props直接调用方法就会触发一个action返回一个新的state
一个页面的使用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
import React, {Component} from 'react'; import {View, Text, StyleSheet, Button} from 'react-native'; import {connect} from 'react-redux'; import actions from '../action'; class TrendingPage extends Component{ render(){ const {navigation} = this.props; return ( <View style={styles.container}> <Text style={styles.welcome}>TrendingPage</Text> <Button title={'change theme to orange'} onPress={ ()=>{ this.props.onThemeChange('orange'); } } /> </View> ); } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems:'center', backgroundColor: '#F5FCFF', }, welcome:{ fontSize: 20, textAlign: 'center', margin: 10, }, }); const mapDispatchToProps = dispatch => ({ onThemeChange: theme => dispatch(actions.onThemeChange(theme)), }); export default connect(null, mapDispatchToProps)(TrendingPage); |