Head First:Redux

作者: sidiWang | 来源:发表于2016-07-26 22:52 被阅读715次

一.什么是Redux?

Redux是最近很火的一个前端数据流框架,之前接触过Flux应该很熟悉了。Redux可以看作是Flux的一种实现。Redux并不是React的一部分,它们没有任何关系。对于单页面运用来说,Redux是利器。其实对于Redux,官方文档已经非常详细。本文主要讲解React以及RN中如何使用Redux。下面我们就来一点一点揭开Redux的神秘面纱。

二.三大原则

单一数据源

Redux会把数据储存在一个object tree中,并且这个object tree只存在于一个单一store中。也就是说,Redux会把所有的数据存到一个单例里面,然后我们各自组件根据自己的需要按需来获取。这点与Flux不同,Flux存在着许许多多的store。

state只读

如果想改变store里面的state,只能通过发送action,没有第二种方式。这和Flux是一样的。在Redux和Flux中都是单向数据流。

纯函数执行修改

使用reducer来改变state tree。reducer只能是纯函数,不能进行任何副操作。输入相同输出也必定相同。

三.元素

Action

和Flux一样,action是一个纯对象,它接收一个数据返回一个带有type字段的对象,形如下:

{

type:RECEIVE_DATA,

data:'data'

}

我们定义一个只读变量RECEIVE_DATA(一般大写)来表明action的type,然后用一个data来储存传过来的数据。在你想要改变数据的时候(比如网络请求),我们会通过某种方式将action中的数据传到store。

Action Creator

action通过action creator创建,action creator是一个纯函数。它接收一些参数(比如json数据),生成相应的action对象。形如下:

function Receive_data(data){

return{

type:RECEIVE_DATA,

data:data

}

}

在这里我们简单返回一个带type和data的action。

在Flux中,action creator需要做dispatch操作,行如下:

function Receive_data(data){

dispatch({

type:RECEIVE_DATA,

data:data

})

}

dispatch是一个用来发送action的函数,它会把action传递到redux。而在redux中,我们需要自己发起dispatch动作。

Reducer

Redux中,reducer是一个纯函数。它接收两个参数,一个原来的state和一个发起的action。当我们执行dispatch(action)之后,会把action传入reducer。由于Redux中state是唯一的,reducer会根据传入的action.type判断传过来的是哪一个action,然后根据action所携带的data更新state的某一部分。

要注意,由于state是可读的,我们并不能直接对state进行操作。这里我们使用Object.assign和ES7对象展开语法对原来的state进行拷贝,并根据action修改其相对应的部分。最后返回一个全新的state对象。

对于Flux,并不存在reducer,取而代之的是一个叫Dispatcher的东西,在这里我们主要讲Redux的相关内容,只是拿Flux来作对比,就不过多赘述Flux的相关内容。

Stroe

Redux中,store存储着单一state。可以把store看成一个单例对象,每次dispatch(action)之后,在reducer里生成新的state对象,最后用新的state对象替换掉原来在store里的旧state对象。store通过reducer创建。reducer不是唯一的,有时候我们为了拆分数据处理逻辑,会创建多个reducer,我们可以通过redux为我们提供的combineReducers来合并多个reducer。一般我们会这么写

这样我们就把两个reducer合并在了一起,然后我们导出reduces,在你需要创建store的地方使用reduces来创建

import { createStore } from 'redux'

let store = createStore(reduces)

我们可以调用store.getState(),拿到我们的state。

console.log('store',store.getState())

//打印出来为

{

textChange:{Text:[]}

todoApp:{todos:[]}

}

可以看到combineReducers会把传入的reducer的方法名生成state中数据对应的key,我们取数据的时候得像state.textChange.Text这样来取。

Flux中的store并不是单一的。在Flux中,store需要自己实现数据处理函数,并在合并成功以后主动发送事件更新UI。Flux的store看起来像这样的

var ListStore=assign({},EventEmitter.prototype,{

items:[],

getAll:function(){

returnthis.items;

},

addNewItemHandler:function(text){

this.items.push(text);

},

emitChange:function(){

this.emit('change');

},

addChangeListener:function(callback){

this.on('change',callback);

},

removeChangeListener:function(callback){

this.removeListener('change',callback);

}

AppDispatcher.register函数在接收到action的时候,会根据action.type去调用对应的store。而Redux则没有这么繁琐,简化了很多东西。

四.搭配React-Native

使用

之前我们根据reducers创建了store实例,理论上来说我们可以通过store.dispatch(action)去更新数据,但真正在RN中,我们不直接操作store。Redux给我们提供了Provider和connect帮助我们连接RN。

import{ Provider ,connect} from'react-redux'

首先我们需要提供一个select函数作为connect一个参数。select会接收到一个全局state,通过自身组件的情况,select返回自身组件中需要用到的props;connect的第二个参数为你需要连接到Redux的Component。调用connect之后,connect会把select筛选后的state和dispatch传入我们自己的组件中。

然后我们用Provider作为顶层组件,把刚刚创建好的store传入Provider的store属性,并把连接后的组件AppConnect包在Provider里面。注意:Provider只能有一个子组件。

Provider在这里的作用就是将我们创建的store传递给connect包装之后的组件(把store.getState()传入select函数),然后组件根据select拿走自己需要的数据。AppConnect就是包装后的SimpleApp。在SimpleApp中,我们可以直接用this.props.dispatch(action)发起action和this.props.Text拿到我们的数据。

数据流

Redux的数据流是单向的,如图:

这是同步action的情况。这里的Smart Component就类似于Provider。Smart Component存储着整个store。Smart Component会把dispatch作为默认props传给子组件。dumb Component会根据select函数选择自己需要的props。

示例

说了太多,不如实践。下面带大家做一个添加删除列表的小程序。

实现一个ListView,当我们点击点我的时候,向ListView的dataSource里面插入一个字符串。点击字符串的时候,把它从列表里面移除。很简单,现在我们用Redux实现。

首先我们要创建两个action,一个添加action,一个删除action。创建一个js file命名action

action.js

type是必须的,addTextAction的message用于保存我们想要传入state的数据。deleteTextAction保存我要删除数据的索引。

然后我们来创建reducer,新建一个js file命名reducer。在这里我们的reducer需要处理两个action,但是并不需要逻辑分离,所以:

reducer.js

之前说过使用combineReducers是为了合并多个reducer,并把传入的key作为state中数据所对应的key,建议这么来写。在这里我们把数据在原state的基础上进行了拼接和删除,并返回一个新的state。

最后我们照之前的说的,根据reduces生成store,并把store和redux连接起来。连接方法前面又讲,这里只展示组件。

index.ios.js

在点击点我按钮的时候,我们发送addTextAction,并传入WSD。这是数据就会顺着action,来到reducer,再来到store,最后子组件的props改变,重新渲染。

Cell.js

在ListView的每一个Cell点击事件中,我们发送deleteTextAction来固定删除index为1的元素。当然正常你应该传入rowId,并根据rowId来删除相关的元素,这里我们简单处理。

五.异步Action

Redux本身可以很好的处理同步事件,但其实大多数时候,我们都需要处理一些异步的事情。比如网络数据解析。Redux为我们提供了一些中间件来处理各种复杂的情况。

Middleware说明

关于Redux的middleware,官方给出了两种实现。一种是使用新的函数链式替换原本的dispatch。比如

类似于循环替换store,每一次传入middleware的store都是之前middleware包装过的store。

第二种是利用函数柯理化,这种类似于官方实现。

myMiddleware.js

我们利用箭头函数使其柯理化,首先把原始的store.dispatch赋值给dispatch变量,然后遍历传入的middlewares。在循环中,把store和dispatch传入,最后返回一个包装过的函数action=>{function(){...}},再赋予dispatch,然后再把新的dispatch传入下一个中间件。

当然这并不是官方完整的实现,具体区别请看Redux官方文档middleWare一节。

异步

我们需要引入thunkMiddleware来执行异步操作,并把store用中间件包起来。

import thunkMiddleware from 'redux-thunk'

import { createStore, applyMiddleware } from 'redux'

let store = applyMiddleware(thunkMiddleware)(createStore)(reduces)

thunkMiddleware的具体做法是根据dispatch传递进来的action,判断如果该action是一个方法,并且方法返回的是一个Promise对象,就会传入dispatch并且执行异步操作。真正把action传递到reducer是在异步action返回的方法里面。

这是一个最简单的异步action。在我们需要请求网络的地方,使用dispatch(fetchPosts('www.xxxxxxx.com')),最后在执行完异步操作之后别忘了调用dispatch去发起一个普通action,真正将数据传递到store。

异步数据流

从Actions->API Wrapper->API Service->API Wrapper->Actions这一步都是thunk帮我们做的事情。完成之后我们只需要像以前一样正正常常的发送我们的同步action就OK了。

最后,我们还是一如既往的奉上公众号二维码,喜欢就关注吧,我们会不定期推送相关技术文章,谢谢支持。

相关文章

  • Head First:Redux

    一.什么是Redux? Redux是最近很火的一个前端数据流框架,之前接触过Flux应该很熟悉了。Redux可以看...

  • 2018-12-11

    head first html css word书籍 http权威指南 head first设计模式

  • HTML+CSS

    (待续。。。) 1.Head First HTML与CSS(第2版) [Head First HTML and C...

  • Head First C 学习之K&R C 、ANSI

    @(C语言)[学习笔记, Head First C, C语言]起于Head First C 第2页 下, 书中简介...

  • 设计模式--策略模式

    ps:本文主要来源于Head First 设计模式(抄Head First的),如有不懂请购买原书观看。 策略模式...

  • Head First Java(一)基本概念

    从今天开始读《Head First Java》一书,并开设了同名专题 Head First Java。计划在 1 ...

  • Head First Python

    下载地址:Head First Python一本免费的电子书,胜过一杯付费的咖啡

  • Head First Java

    变量类型 变量类型有两种:一种是清凉的 primitive 主数据类型,一种是香辣的对象引用。变量必须拥有类型,另...

  • Head First Programmer

    目录 写在最前面

  • head-first

    设计模式

网友评论

  • 十旋转45度:提个小小的建议,代码块有自己的转化符```的...
  • promiseid:讲得藏藏哒!很实用,期待新的rn文章

本文标题:Head First:Redux

本文链接:https://www.haomeiwen.com/subject/spmljttx.html