众所周知,React中数据通讯是单向的,即父组件能够经过props向子组件传递数据,而子组件却不能向父组件传递数据。要实现子组件向父组件传递数据的需求,须要父组件提供一个修改数据的方法,当页面愈来愈多的时候,数据的管理就会变得异常复杂。
而且,每次数据的更新都须要调用setState,特别是涉及到跨组件通讯的问题就会很麻烦。在React开发中,为了解决跨组件通讯的问题,业界开发了一大批状态管理框架,目前比较经常使用的React状态管理框架有Flux、Redux和Mobx等几个。
其中,Flux是Facebook用于创建客户端Web应用的前端架构,它利用一个单向数据流的方式补充了React的组合视图组件,解决了MVC技术架构中数据流管理混乱的问题。Redux则是由Dan Abramov开源的一款前端状态管理框架,Redux框架由Action、Store和Reducers三部分组成,全部组件的数据都存储到Store对象中,每一个组件只须要改变Store中的数据,当Store数据发生变化时就会其余订阅的组件执行数据更新。Mobx是一个面向对象的状态管理框架,它与Redux的最大区别是能够直接修改数据,精准的通知UI进行刷新,而不是Redux的广播。
能够发现,Redux特别适合用在须要集中式管理数据场景中。多个组件使用同一个数据源,维护同一个数据样本,进而保持各个组件之间数据的一致性。react-redux是Redux状态框架在React中的技术实现,对于熟悉Redux状态管理框架开发者来讲,学习react-redux将会显得很是容易。
在Redux状态框架中,Redux将状态管理分为Action、Store和Reducers三部分。其中,Redux将应用程序的状态存储到Store中,组件经过dispatch()方法触发Action,Store接收Action并将Action转发给Reducer,Reducer根据Action类型对状态数据进行处理并将处理结果返回给Store,其余组件经过订阅Store状态的来刷新自身的状态,整个框架的工做流程如图3-9所示。前端
下面以计数器为例来讲明Redux的基本使用。首先,建立一个action.js文件,用来存放Action行为事件,以下所示。react
export const ADD = 'ADD' export const MINUS = 'MINUS'
而后,建立一个reducer.js文件,用来处理业务逻辑的更新,并将处理的结果返回给Store,以下所示。redux
import {ADD, MINUS} from './action'; function reducer (state = {count: 0}, action) { switch(action.type) { case ADD: return {count: state.count + 1} case MINUS: return {count: state.count - 1} default: return state } } export default reducer;
Reducer是一个纯函数,接收State和Action两个参数。其中,State是旧的状态,不能够直接修改,Reducer会根据Action的类型来生成不一样的新State,并将结果返回给Store。
接下来,建立一个全局的Store对象,用来存放应用的状态数据,建立时须要使用Store提供的createStore()方法,以下所示。架构
import { createStore } from 'redux' import reducer from './reducer'; const store = createStore(reducer) export default store
除了createStore()方法外,建立的Store还有如下几个方法能够调用。框架
为了实现计数器加减的功能,还须要在组件的生命周期函数中添加订阅事件,并在组件销毁时解决订阅,以下所示。ide
class CounterPage extends React.Component { constructor(props){ super(props) this.state = { number: store.getState().count } } componentDidMount () { this.unSubscribe = store.subscribe(() => { this.setState({ number: store.getState().count }) }) } componentWillUnmount () { this.unSubscribe && this.unSubscribe() } render() { return ( <View style={styles.ct}> <Text>{this.state.number}</Text> <Button title="加1" onPress={() => store.dispatch({type: 'ADD'})}/> <Button title="减1" onPress={() => store.dispatch({type: 'MINUS'})}/> </View> ); } } const styles = StyleSheet.create({ ct: { flex: 1, justifyContent: 'center', alignItems: 'center', }, }); export default CounterPage;
在上面的代码中,咱们经过store.getState()方法来获取最新的State,而执行加减操做时经过store.dispatch()方法派发Action给Store。能够发现,在类组件中使用Redux仍是挺繁琐的,须要开发者本身管理组件的状态数据,而若是改用React Hook就要简单许多。
在React Hook中使用Redux须要使用react-redux库提供的useSelector()与useDispatch()两个函数。其中,useSelector()函数能够用来获取状态值,而useDispatch()则能够用来修改状态数据,以下所示。函数
import { useSelector, useDispatch } from 'react-redux' const CounterPage = () => { const count = useSelector(state => state.count) const dispatch = useDispatch() return ( <View style={styles.ct}> <Text>{count}</Text> <Button title='加1' onPress={() => dispatch({type: 'ADD'})}/> <Button title='减1' onPress={() => dispatch({type: 'MINUS'})}/> </View> ); } const styles = StyleSheet.create({ …. //省略代码 }); export default CounterPage
能够发现,相比于类组件来讲,使用React Hook实现就要简洁许多。首先,咱们使用useSelector()函数获取Store中的状态,而后再使用useDispatch()函数派发事件。
最后,使用Redux在让不一样组件之间共享状态数据时,还须要使用react-redux库提供的Provider包裹应用组件,以下所示。学习
const App = () => { return ( <Provider store={store}> <CounterPage /> </Provider> ); };
从新运行代码,就实现了计数器的功能,以下图所示。flex
最后,须要说明的是,使用Redux进行状态管理时,应注意如下几点:
• 应用中有且仅有一个Store,该Store存储了整个应用的状态。
• State是只读的,修改State只能经过派发Action事件,为了描述Action改变State的过程,须要使用Reducer纯函数。
• 单一数据源让多个React组件之间的通讯更加方便,也有利于状态的统一管理。this