react-native redux使用指南

demo 地址:react

https://github.com/chris6605/react-native-reduxgit

1 >> 什么是redux ? 你的项目需不须要redux?github

有个大神说过? 若是你以为你的项目不须要redux, 那么你就真的不须要去用 redux.npm

redux 究竟是什么呢? 其实就是用来统一管理整个应用 State 的, 将全部的 state 变化进行统一的流程处理, 使应用的 state变化清晰可见.redux

如图 : 使用redux和不使用组件之间的通讯方式的不一样 react-native

 

 

在React中,数据在组件中是经过 props 单向流动的。数据从父组件流向子组件,因为这个特征,两个兄弟组件之间的通讯并非那么清楚。
React并不建议直接采用组件到组件的通讯方式,须要提一点的是, 在使用 redux 以后你就不能直接调用组件的方法了, 好比你写个弹窗有个 show() 方法, 你在使用的地方经过引用 this.xxxDialog.show()是不会起做用的, 须要严格遵照单向数据流的思想. 尽管它有一些特性能够支持这么作(好比先将子组件的值传递给父组件,而后再由父组件在分发给指定的子组件)。这被不少人认为是糟糕的实践方式,由于这样的方式容易出错并且会让代码向“拉面”同样不容易理解。
固然React也没有直接建议如何去处理这种情形, React 官方是这么解释的:设计模式

对于非父子关系的组件,你能够本身创建一个全局的事件系统,Flux的模式也是一种可行的方式。app

Redux的出现就让这个问题的解决变得更加方便了。异步

Redux提供一种存储整个应用状态到一个地方的解决方案(能够理解为统一状态层),这个存储全部应用状态的地方称为“store”,组件发生事件时不会再 setState, 而是由 store 分发(dispatch)一个事件(action),  组件将状态的变化通知给store,而不是直接通知其它的组件, store会根据 action 的类型来调用对应的 reducer(纯函数, 告诉 state 该作出什么变化), reducer 会根据 action 的类型, 接收一个旧的 state, 返回一个新的 state,  store 会收集到全部 reducer的state, 最后更新 state,  组件内部依赖的state的变化状况就能够经过订阅 store 来实现。如图所示:ide

 

 


使用Redux,全部的组件都从store里面获取它们依赖的state,同时也须要将state的变化告知store。组件不须要关注在这个store里面其它组件的state的变化状况,Redux让数据流变得更加简单。这种思想最初来自Flux,它是一种和React相同的单向数据流的设计模式。

若是你的页面单一页面, 功能简单, 状态很少变, 没有涉及多个页面之间的交互, 那么你就不用往下看了, 你真的不须要用 redux这么重量级的东西, 可是好比作多语言, 换肤功能, 字体切换也能够考虑用redux.

 

redux 的三原则

1. Single source of truth
单一数据源。整个应用的state,存储在惟一一个object中, 那就是 store, 一个应用有且只有一个 store

2. State is read-only 
状态是只读的。惟一能改变state的方法,就是触发action操做。不要想着再去 setState 了, 用了 redux 以后你改变 state 惟一的方法就是 dispatch 一个 action, action是什么? 别急,下面再说

3.  Changes are made with pure functions
在改变state tree时,用到action,同时也须要编写对应的reducers才能完成state改变操做。而且 reducer 必定要是一个纯函数, 不要在里面作一些乱七八糟的骚操做

2 >> 什么是 Action?   reducer ?   store ? provider? 

Action  动做 :好比登陆操做  退出登陆操做 添加待办 删除待办均可以定义为一个 action

example:

 

 
 
 
 
严格的来说这应该叫作ActionCreactor , 他返回的那个对象才叫 action, action 就是一个纯对象, 描述正在发生的事情, 也就是触发的操做, 好比这个就是描述正在登陆的过程, 只不过我传递的有个 data, 里面存的是登陆状态, 一会再讲这个data 怎么用, 总之记住一句话, action 就是一个纯对象, 描述正在发生的事件.必需要有一个 type 属性, types 那个就是一个常量, 用来标识和区分你的 action 的类型, 好比是登陆仍是登出, 是添加仍是删除.
 
Store 全局惟一的一个对象 能够看做应用 state 的集合 , 也就是说你在任意组件中均可以经过 store 拿到你想要的 state

这就是一个完整的 store 的建立过程, createStore 是redux 里提供的函数, 接受初始状态,  reducer( reducer 能够有多个, 这里是合并多个 reducer 的 RootReducer ),   中间件.

store 有什么用呢? store 就是一个保存着整个 APP 的全部state 的对象, 顾名思义, 就是一个仓库嘛, 在任何一个组件中均可以经过store 来获取任何一个 state,

Reducer  是一个纯函数, 不要在这里作逻辑操做的事情, 他就是根据一个 action 的 type 返回一个新的 state 必定要保证其纯洁性

 异步Action

// 异步的Action 须要返回的是一个 function 在 createStore 时由middleWare 作处理 普通的action 直接返回纯对象便可
  export function requireLogin(info) {
  return LoginApi(info);
  }

 

 

这其实就是一个 action(只不过是个异步的 action , 以下图上面是一个普通的同步 action  , dispatch 这个 action 立刻就执行, 返回新的 state, UI 更新, 可是异步的不一样, 不能立刻获取新的 state

这里模仿请求的百度, 请求完成登陆成功, 异步的 action 返回的不是纯对象了, 而是一个函数, 就是上图那个函数, 另外在建立 store 的时候还要使用middleware 中间件, 这样才能执行异步操做)

 

废话都说的差很少了, 相信你对 redux大概有个了解了, 起码对 action reducer store 这三个概念有个印象, action 就是描述一件事情发生的对象, reducer 就是个纯函数, 接受旧的 state 和一个 action, 返回一个新的 state 到 store, store 就是全局惟一的一个仓库,存储着应用全部的 state

 

Provider

provider主要有两个功能 

  • 在原应用组件上包裹一层,使原来整个应用成为Provider的子组件
  • 接收Redux的store做为props,经过context对象传递给子孙组件上的connect

context可使子孙组件直接获取父级组件中的数据或方法,而无需一层一层经过props向下传递。context对象至关于一个独立的空间,父组件经过getChildContext()向该空间内写值;定义了contextTypes验证的子孙组件能够经过this.context.xxx,从context对象中读取xxx字段的值。

总而言之,Provider模块的功能很简单,从最外部封装了整个应用,并向connect模块传递store。

而最核心的功能在connect模块中。

connect的做用:

一、connect经过context获取Provider中的store,经过store.getState()获取整个store tree 上全部state。
二、connect模块的返回值wrapWithConnect为function。
三、wrapWithConnect返回一个ReactComponent对象Connect,Connect从新render外部传入的原组件WrappedComponent,并把connect中传入的mapStateToProps, mapDispatchToProps与组件上原有的props合并后,经过属性的方式传给WrappedComponent

 

下面进入实战

1. 建立你的项目, 新建以下文件夹

constants actions reducers store pages 

这里说一下 不作异步请求的话 就不用像我那样用中间件 action 返回函数, 直接return 一个对象, 只有一个 type字段就OK  项目的在 Github 上本身能够看一下

 

 2 npm install  react-redux  redux   redux-logger(这个会打印你的全部 state和 action变化 , 建议使用)    redux-thunk(中间件, 用于异步操做)    react-navigation(若是你要作多个页面跳转就install)

3. 新建一个 Root.js

用 provider 包住你的 APP, 这样全部的组件就均可以获取到 store 的 state 变化了 注意要传递 store

而后就是把 Root.js 当成 App.js同样, 放到你的 index.js里便可

4. 接下来就是编写 action  reducer  store 了

举个简单的加减的同步操做的例子

 actionCreactor: 函数返回一个 action

 reducer:

这里要提一下, reducer 能够有不少个, 拆分 reducer 对一个不一样的操做, 而后用combineReducers 合并全部的 reducer 到 rootReducer, 以下图:

我我的习惯叫 xxxReducer , 在组件中使用的时候, 能够 state.xxxReducer.xxx 便于区分

 

5. 在 page里怎么使用 

example登陆的操做

下面登陆就这么简单了只须要一句 this.props.loginAction() , 登陆的逻辑在 loginRequest 里, 发起登陆操做便可, 也算能够给 page解耦, 

 

 

 

这里要注意一下 bindActionCreactors 他的做用是把 dispatch 函数无感知的传递给子组件, 在子组件里就能够 dispatch 一个 action, 固然你也能够经过 props 把dispatch 函数传递给子组件, 只是不优雅, 该函数接受两个参数, 第一个参数能够是函数或者对象,通常是一个 actionCreactor, 返回的也是一个函数或者对象, 第二个参数是 dispatch,

bindAction: {login_doing: ƒ, login_done: ƒ, login_err: ƒ, login_out: ƒ, requireLogin: ƒ}
* {
addTodo : text => dispatch(addTodo('text'));
removeTodo : id => dispatch(removeTodo('id'));
}
至关于 dispath 一个 action
 

这里有个 connect 函数 他的做用就是把当前组件和 store 链接, 而后就能够获取 store 里的 state, store 中的 state 在 dispatch一个 action 以后, 在 reducer 的做用下产生新的 state 返回到 store, 这时你的组件也能接收到新的 state, 不过是以 props 的形式, 如上 connect 函数接受两个参数, 第一个参数接受两个参数分别是 mapStateToProps (名字就表示了他的意思, 你须要获取的 state 会经过props 的形式传递到你的当前组件) matchDispatchToProps 这个是你须要的dispatch 的 action , 我更喜欢直接在发生事件的时候去this.props.dispatch(action),  固然这种不规范, 大家仍是用matchDispatchToProps 而后就能直接 this.props.loginAction()就 OK 了

 

这个是那个简单的同步操做加减的, count就是那个 state, 这里已经经过 mapStateToProps 获取了, 因此使用的时候就能够this.props.count , 当你 dispatch一个 action 的时候, reducer 会改变他的值, 返回到 store , 最后经过 connect, store 会把这个改变后的 state 更新到这里

 

 

 

固然在其余地方也能够dispatch 这个 action, 这里的 count 也会变化, 固然在其余地方也能够获取到这个 count, 这就是他的强大之处, 任何地方都能获取到 store 中存储的 全部的state, 在任何地方均可以 dispatch 一个你想要 dispatch 的 action, 能够跨组件的操做和数据传递提供了很大的便利性和可维护性, 因此这也是他适用于逻辑复杂的应用的缘由 

 下面附上那个 redux-logger 的日志 里面有store 里详细的 state 变化  以及发起的每个 action 因此说对于解决 bug 调试起来很省事

 

是否是一目了然, 你触发了哪一个 action , 改变了什么状态以及最终的状态, 传递的数据都清晰明了,

总结一下吧, redux 很强大, 也很易用, 下面是一个流程图

store 就是仓库

action 就是描述事件发生的对象

reducer 就是事件发生以后如何改变state 的一个纯函数

相关文章
相关标签/搜索