React Native 我觉得是一个非常不错的框架,我学习和使用React Native已经有一段时间了,我最大的一个感受就是,用React Native 开发App的速度非常快,一方面npmjs上已经有非常多的开源库,而且在开发上ES6的各种扩展也大大的简便了我们的开发。React Native的开发过程中可以使用npmjs上几乎所有的lib和框架,Redux就是其中一个

这篇文章主要是想说一下我在学习React Native中Redux是一个什么样的东西,网上也能搜到非常多的资料,这篇主要是在谈谈我自己的对Redux的理解。

React Native 里面的Component

React Native开发里面Component是一个很重要的东西,我觉得它和Android 里面的Fragment非常类似,是一个带有状态(state)的一个组件,当然还有一个props。在我的理解中,Component是一个由state驱动的组件,就是Component可以根据不同的state来显示不同的View

问题来了,不同的Component之间state都相互独立,不共享的,那么App中有些状态就是统一的,而且只有一个的,比如:用户是否已经登录,或者用户是否是会员或Vip之类的。。。那么像这些状态应该怎么统一维护呢?

有一个办法就是,用户登录成功以后用AsyncStorage来保存用户信息,这种思想是直接源自于App原生开发中的,用一个单例来维护全局的用户信息:

1
2
3
4
5
//保存用户信息
AsyncStorage.setItem("_user", JSON.stringify(user));
//获取用户信息
let json = await AsyncStorage.getItem(KEY_USER);

Redux来了

上面说的方法是“笨”方法,Redux可以非常好的来帮助我们来维护App中的状态。我也不想用别人文章里写过很多的方式来描述Redux,我对于Redux的理解就是,定义里了一套方式来帮助开发者更好的管理React Native应用中的状态,而且是全局状态的维护。

上面说了很多“废话”,现在来说重点了

首先,要了解Redux,我们必须先了解一下Redux中有哪几部分重要的东西,一共就3种:

  • 全局唯一的Store,这只是一个容器
  • Store里面保存的各种状态,需要我们定义Reducers来创建和维护,也就是说Reducers中描述的就是App中的各种状态,这也是最重要的部分
  • 还有各种Actions,就是用来改变Reducers中的状态的

总结一下上面说到的3点,用简单的话来描述Redux就是,Redux会帮我们在App中创建一个全局唯一的Store,然后我还需要用reducer来创建各种状态,比如用户的登录状态等等,状态不可能永远不变,比如当用户点击了“登录”按钮,登录成功以后,就需要将Actions以及用户的登录信息发送到StoreStore中的状态就会更新

创建和使用Store

Redux框架已经提供了createStore方法来帮助我们创建一个全局唯一的状态维护容器Store,然后就是使用Store, 使用的时候必须要用Provider组件将我们自己写的Component组件包起来,Provider组件还必须要包含一个store 属性(props)将我们创建的Store对象传入。再多说一点,查看源码就明白,Provider组件其实就做了一件非常简单但重要的事情:将我们创建的Store传给每一个子(Child)组件(Component)。如下面代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//创建Store
import { createStore } from 'redux'
import {Provider} from 'react-redux';
import loginReducer from './reducers'
let appStore = createStore(loginReducer)
//使用Store
const AppWithStore = () => (
<Provider store={appStore}>
<App />
</Provider>
);
export default AppWithStore;

像上面那样使用Store后,我们在App组件中也还是不能使用Redux的store,比如发送Actions或读取Store中的状态。还需要有一点小改动就是,在export App的时候需要用react-redux提供的connect高阶函数来“建立连接”,这是react-redux提供的方便我们写的Component操作和获取Store中的状态。

可以看到下面的代码,connect函数非常奇怪,后面跟了两对括号,其实原理也蛮简单的,就是connect(mapStateToProps, mapDispatchToProps)的返回值也是一个function,并且这个function接受的参数就是一个Component对象。connect函数主要做的事情就是将Component做一次Wrap,对这个好奇的小伙伴可以去看看react-redux框架中的connect.jsconnectAdvanced.js文件中的代码

1
2
3
4
5
6
7
8
9
import {connect} from 'react-redux'
...
//定义App
class App extends Component{
...
}
export default connect(mapStateToProps, mapDispatchToProps)(App);

创建reducers

上面说的创建和使用Store是将Redux如何应用到我们的App中,具体要创建和维护我们需要的App中状态,还需要我们自己来开发reducers。首先,因为在开发过程中会有写很多的Redux,所以最好先新建一个reducers目录,然后分别创建index.jsloginRedux.js文件:

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
//index.js
import {combineReducers} from 'redux'
import loginState from './loginRedux'
export default combineReducers({
loginState,
});
//loginRedux.js
export const loginActions = {
LOGIN: 'LOGIN',
LOGOUT: 'LOGOUT',
};
const initialState = {
login: false,
};
export default function login(state = initialState, action) {
switch (action.type) {
case loginActions.LOGIN: {
return {...state, login: true}
}
case loginActions.LOGOUT: {
return {...state, loading: false}
}
default:
return state
}
}

这样文件建好以后就可以使用Redux了,可能一开始接触Redux会觉得比较麻烦,一旦基本的框架搭好以后,后面的开发就会变得简单。接下来,可以在LoginPage.js中直接使用了

  • 首先把loginRedux的Actions 引用进来,import {loginActions} from '../reducers/loginRedux'
  • 然后你就可以直接使用this.props.dispatch({type: loginActions.LOGIN})来更新Store中的login状态

这里有两个疑问点:

  • dispatch函数哪里来的?其实这个函数就是一开始我们创建的那个Store对象的,调用dispatch函数就相当于向Store发了一个指令,让Store更新某些状态
  • Store更新了以后,Component怎么监听到状态改变?答案就是connect函数的参数mapStateToProps,这个函数就相当于告诉Redux,我要监听loginState的变化,而且将Store中的状态loginState 映射(map)到当前Component的props中,字段的名字就叫做loginState(当然你可以改成别的名字)
1
2
3
4
5
const mapStateToProps = (state, props) => ({
loginState: state.loginState,
});
export default connect(mapStateToProps)(DailyList);

总结

对Redux来说,最主要的功能就是帮我们开发JavaScript程序的时候去统一的管理状态(state),提供了流式的状态管理理念,状态(state)被Redux统一保持在一个Store的容器中,如果你要修改Store中的状态,那么你只能通过Store的dispatch函数发送一个Action来修改或更新状态,保证了单向数据流。这篇文章主要是将我理解的最本质的Redux用我自己的话描述出来,可能有些地方不一定正确,如果想完整的了解Redux,可以阅读Redux的中文文档:http://cn.redux.js.org/docs/introduction/CoreConcepts.html