redux异步操作学习笔记

摘要:

  发觉在学习react的生态链中,react+react-router+webpack+es6+fetch等等这些都基本搞懂的差不多了,可以应用到实战当中,唯独这个redux还不能,学习redux还学的挺久的。

  其中困扰我最久的就是redux的异步数据流的处理。难点主要是概念太多,接触的词太多,而且网上的案例看的头都疼,很容易晕,已经晕了好多次了。后来被我简化之后,终于搞懂了,哈哈。!来来来,今天总结一下,希望对大家有所帮助。不过本人主要是介绍redux的异步操作,如果对redux不是很熟悉的,可以看看我之前写的一篇文章http://www.cnblogs.com/xianyulaodi/p/5399264.html

1、redux异步流程简介

先来一张图先,大概介绍一下redux的异步流程:

(图片来自于百度图片)

大概的流程是这样的:

  首先发起一个action,然后通过中间件,这里为什么要用中间件呢,因为这样dispatch的返回值才能是一个函数。通过store.dispatch,将状态的的改变传给store的小弟,reducer,reducer根据action的改变,传递新的状态state。最后将所有的改变告诉给它的大哥,store。store保存着所有的数据,并将数据注入到组件的顶部,这样组件就可以获得它需要的数据了。

2、demo简介

这个demo是我根据官网的async改编的,其实也就是删除了很多其他干扰的东西,让它仅仅是获得一个异步请求。初学嘛,能简单则简单,这样比较明朗。

官网原版的github地址: https://github.com/lewis617/react-redux-tutorial/tree/master/redux-examples/async

我改编的github地址:https://github.com/xianyulaodi/reduxAsync

本文也是通过我自己改的来写的。可以边看代码边看此文,当然可能有些讲的不是很对,欢迎指出

界面如下:

界面很简单,就是通过异步请求,将请求到的数据展现到界面上。可能你会说,不就是一个请求嘛,有啥大不了的。可是这个请求是走了一遍redux的流程的呢,哈哈。

3、代码解析

下面对redux的异步流程做一个小小的解析。期间顺便也回顾一下redux的一些基础知识吧。

3.1 首先从action开始,代码在  action/index.js

 1 import fetch from ‘isomorphic-fetch‘
 2 export const RECEIVE_POSTS = ‘RECEIVE_POSTS‘
 3
 4 //获取新闻成功的action
 5 function receivePosts(reddit, json) {
 6   return {
 7     type: RECEIVE_POSTS,
 8     reddit: reddit,
 9     posts: json.data.children.map(child =>child.data)
10   }
11 }
12
13 function fetchPosts(subreddit) {
14
15   return function (dispatch) {
16
17     return fetch(`http://www.subreddit.com/r/${subreddit}.json`)
18       .then(response => response.json())
19       .then(json =>
20         dispatch(receivePosts(subreddit, json))
21       )
22   }
23 }
24
25 //如果需要则开始获取文章
26 export function fetchPostsIfNeeded(subreddit) {
27
28   return (dispatch, getState) => {
29
30       return dispatch(fetchPosts(subreddit))
31
32     }
33 }

  此次的请求没有用ajax,而是用了fetch,这个稍微了解一下即可,入门比较容易。如上面的redux异步流程图一样,它需要借助一个中间件 middleware。其实异步的精髓也就在这个中间件middleware这里了。搞懂了这个,可以说基本也就搞懂的redux的异步了。所以我会花比较大的篇幅去介绍这个中间件。

middleware有什么用?为什么要引入它呢?

在redux里,action仅仅是携带了数据的普通js对象( plain JavaScript objects)。action creator返回的值是这个action类型的对象。然后通过store.dispatch()进行分发……

action ---> dispatcher ---> reducers

如果遇到异步情况,比如点击一个按钮,希望2秒之后更新视图,显示消息“Hi”。我们可能这么写ActionCreator:

var asyncSayActionCreator = function (message) {
    setTimeout(function () {
        return {
            type: ‘SAY‘,
            message
        }
    }, 2000)
}

  这会报错,因为这个asyncSayActionCreator返回的不是一个action,而是一个function。这个返回值无法被reducer识别。

也就是说,正常来说,action返回的是一个对象,而不是一个函数。如果返回函数,会出现错误。

  而异步操作呢,需要action的返回值是一个函数。那么咋办呢,所以需要引入中间件middleware,它在中间起到了桥梁的作用,让action的返回值可以是一个函数,从而传到

reducer那里。也就是说,中间件是用在action发起之后,reducer接收到之前的这个时间段。

也可以这么说,Middleware 主要是负责改变Store中的dispatch方法,从而能处理不同类型的 action 输入,得到最终的 Javascript Plain Object 形式的 action 对象。

  因此,上面那个ActionCreator就可以改写为这样:因为action的返回值是一个函数。

var asyncSayActionCreator = function (message) {
    return function (dispatch) {
        setTimeout(function () {
            dispatch({
                type: ‘SAY‘,
                message
            })
        }, 2000)
    }
}

中间件是如何工作的

Middleware的中间件有很多,不过我的这个案例只引用了其中的一个,那就是redux-thunk

redux-thunk源码如下:

export default function thunkMiddleware({ dispatch, getState }) {
  return next => action =>
    typeof action === ‘function‘ ?
      action(dispatch, getState) :
      next(action);
}

意思是如果action是一个函数,执行这个action函数,如果不是函数,执行next函数。

具体的原理可以看看这两篇文章:

 Redux学习之一:何为middleware?

 redux 中间件详解:

回到我的项目源代码:

   fetchPostsIfNeeded这里就是一个中间件。redux-thunk会拦截fetchPostsIfNeeded这个action,会先发起数据请求,如果成功,就将数据传给action.从而到达reducer那里。

再来看看reducer 目录为 reducers/index.js

 1 import { combineReducers } from ‘redux‘
 2 import {
 3   RECEIVE_POSTS
 4 } from ‘../actions‘
 5
 6
 7 function posts(state = {
 8   items: []
 9 }, action) {
10   switch (action.type) {
11
12     case RECEIVE_POSTS:
13       // Object.assign是ES6的一个语法。合并对象,将对象合并为一个,前后相同的话,后者覆盖强者。详情可以看这里
14       //  https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
15       return Object.assign({}, state, {
16         items: action.posts //数据都存在了这里
17       })
18     default:
19       return state
20   }
21 }
22
23 //废弃、接收到、开始接受新闻后,将state.postsByReddit设为相关参数
24 function postsByReddit(state = { }, action) {
25   switch (action.type) {
26     case RECEIVE_POSTS:
27       return Object.assign({}, state, {
28         [action.reddit]: posts(state[action.reddit], action)
29       })
30     default:
31       return state
32   }
33 }
34
35 // 将所有的reducer结合为一个,传给store
36 const rootReducer = combineReducers({
37   postsByReddit
38 })
39
40 export default rootReducer

这个跟正常的reducer差不多。判断action的类型,从而根据action的不同类型,返回不同的数据。这里将数据存储在了items这里。这里的reducer只有一个。最后结合成rootReducer,传给store。

store/configureStore.js

 1 import { createStore, applyMiddleware } from ‘redux‘
 2 import thunkMiddleware from ‘redux-thunk‘
 3 import createLogger from ‘redux-logger‘
 4 import rootReducer from ‘../reducers‘
 5
 6 const createStoreWithMiddleware = applyMiddleware(
 7   thunkMiddleware,
 8   createLogger()
 9 )(createStore)
10
11 export default function configureStore(initialState) {
12   const store = createStoreWithMiddleware(rootReducer, initialState)
13
14   if (module.hot) {
15     // Enable Webpack hot module replacement for reducers
16     module.hot.accept(‘../reducers‘, () => {
17       const nextRootReducer = require(‘../reducers‘)
18       store.replaceReducer(nextRootReducer)
19     })
20   }
21
22   return store
23 }
我们是如何在 dispatch 机制中引入 Redux Thunk middleware 的呢?我们使用了 applyMiddleware(),
const createStoreWithMiddleware = applyMiddleware(
  thunkMiddleware,
  createLogger()
)(createStore)

其中,createLogger是一个很便捷的 middleware,用来打印 action 日志。通过使用指定的 middleware,action creator 除了返回 action 对象外还可以返回函数。

这时,这个 action creator 就成为了 thunk。

再来看看界面上的调用:在containers/App.js

部分代码:

  //初始化渲染后触发
  componentDidMount() {
    const { dispatch} = this.props
    // 这里可以传两个值,一个是 reactjs 一个是 frontend
    dispatch(fetchPostsIfNeeded(‘frontend‘))
  }

改变状态的时候也是需要通过dispatch来传递的。

数据的获取是通过provider,将store里面的数据注入给组件。让顶级组件提供给他们的子孙组件调用。代码如下:

import ‘babel-core/polyfill‘
import React from ‘react‘
import { render } from ‘react-dom‘
import { Provider } from ‘react-redux‘
import App from ‘./containers/App‘
import configureStore from ‘./store/configureStore‘
const store = configureStore()
render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById(‘root‘)
)

这样就完成了redux的异步操作。其实最主要的区别还是action里面还有中间件的调用,其他的地方基本跟同步的redux差不多的。搞懂了中间件,就基本搞懂了redux的异步操

作。具体的大家还是需要看一下源码和其他相应的文章介绍。当然,demo是不够完善的,因为缺少请求发送失败等等的处理。

再附上一张图来结束今天的学习笔记:

今天的总结就到这里先,感觉自己总结的有点乱。刚好最近用react写了一个小小的项目,下一步将异步和同步结合起来,真正用到实战中,到时候再将这篇博客完善和补充。

由于是初学异步的操作,所以可能有些地方自己总结的错了。有误之处,欢迎指出。如果对于中间件还有很多困惑的同学,不妨看一下下面的链接。

参考:

http://www.aliued.com/?p=3204

http://www.cnblogs.com/bingooo/p/5500108.html#top

http://cn.redux.js.org/

https://segmentfault.com/a/1190000003746223

https://zhuanlan.zhihu.com/p/20597452?utm_source=tuicool&utm_medium=referral 

 

如果您觉得文章有用,也可以给咸鱼老弟发个微信小额红包鼓励鼓励,哈哈

时间: 2024-12-14 16:48:12

redux异步操作学习笔记的相关文章

react之redux的学习笔记

主流的数据框架:Flux (单向数据量,比较重大,实用性不强) reFlux redux(简单 单一状态树) mvc model: 数据 view: 显示 controller: 管理(action) npm install react-redux redux

React+Redux学习笔记:React+Redux简易开发步骤

前言 React+Redux 分为两部分: UI组件:即React组件,也叫用户自定义UI组件,用于渲染DOM 容器组件:即Redux逻辑,处理数据和业务逻辑,支持所有Redux API,参考之前的文章:Redux学习笔记:Redux简易开发步骤 而React+Redux是以上两部分结合起来,方便在React中使用Redux,专用库为React-Redux.js.React-Redux.js新增了一些新方法: Provider:容器跟组件,可直接把外部的state传递给所有子组件和UI组件: m

udacity android 学习笔记: lesson 4 part b

udacity android 学习笔记: lesson 4 part b 作者:干货店打杂的 /titer1 /Archimedes 出处:https://code.csdn.net/titer1 联系:1307316一九六八 声明:本文採用下面协议进行授权: 自由转载-非商用-非衍生-保持署名|Creative Commons BY-NC-ND 3.0 ,转载请注明作者及出处. tips:https://code.csdn.net/titer1/pat_aha/blob/master/Mar

hadoop 学习笔记:mapreduce框架详解

hadoop 学习笔记:mapreduce框架详解 开始聊mapreduce,mapreduce是hadoop的计算框架,我 学hadoop是从hive开始入手,再到hdfs,当我学习hdfs时候,就感觉到hdfs和mapreduce关系的紧密.这个可能是我做技术研究的 思路有关,我开始学习某一套技术总是想着这套技术到底能干什么,只有当我真正理解了这套技术解决了什么问题时候,我后续的学习就能逐步的加快,而学习 hdfs时候我就发现,要理解hadoop框架的意义,hdfs和mapreduce是密不

IOS学习笔记 -- 多线程

多线程1.多线程的原理 1>.同一时间,CPU只能处理1条线程,只有1条线程在工作(执行) 2>.多线程并发(同时)执行,其实是CPU快速地在多条线程之间调度(切换) 3>.如果CPU调度线程的时间足够快,就造成了多线程并发执行的假象如果线程非常非常多,会发生: 1>.CPU会在N多线程之间调度,CPU会累死,消耗大量的CPU资源 2>.每条线程被调度执行的频次会降低(线程的执行效率降低) 2.多线程的优缺点 1>.多线程的优点 能适当提高程序的执行效率 能适当提高资源

ArcGIS API for JavaScript 4.2学习笔记[0] AJS4.2概述、新特性、未来产品线计划与AJS笔记目录

放着好好的成熟的AJS 3.19不学,为什么要去碰乳臭未干的AJS 4.2? 诸君,我喜欢嫩的--呸呸呸 诸君,我喜欢3D咋了?新事物会替代旧事物不是~ ArcGIS API for JavaScript 4.2概述 AJS 4.2,即ArcGIS API for JavaScript 4.2,是美国ESRI公司针对WebGIS市场推出的.利用JavaScript和Dojo开发的一款产品,它在2016年12月发布.而AJS 4.0 beta则在一年前就发布了. 关于AJS3和AJS4选择的问题,

backbonejs学习笔记

Backbone是一个轻量级的前端MVC框架,用于结构化管理页面中的大量JS,建立与服务器.视图间的无缝连接,为构建复杂的应用提供基础框架.最适合的应用场景是单页面应用,并且页面上有大量数据模型,模型之间需要进行复杂的信息沟通.backbone所依赖的underscore类库提供了60多个函数用于处理数组操作.函数绑定以及javascript模板机制. 在Backbone中,DOM选择器.DOM事件和AJAX,都使用了jQuery的方法.如果不想使用jQuery或Zepto,而是使用其它的.或自

DBus学习笔记

摘要:DBus作为一个轻量级的IPC被越来越多的平台接受,在MeeGo中DBus也是主要的进程间通信方式,这个笔记将从基本概念开始记录笔者学习DBus的过程 [1] DBus学习笔记一:DBus学习的一些参考资料[2] DBus学习笔记二:什么是DBus?[3] DBus学习笔记三:DBus的一些基本概念 一些基本概念的解释和翻译:http://blog.mcuol.com/User/AT91RM9200/Article/12816_1.htmhttp://www.cnblogs.com/wzh

nBodyCS&lt;I&gt;学习笔记之计算着色器

nBodyCS<I>学习笔记之计算着色器 Nvidia-SDK(1) 版权声明:本文为博主原创文章,未经博主允许不得转载. DirectX一直是Windows上图形和游戏开发的核心技术.DirectX提供了一种在显卡上运行的程序--着色器(Shader).从DirectX11开始,DirectX增加了一种计算着色器(Compute Shader),它是专门为与图形无关的通用计算设计的.因此DirectX就变成了一个通用GPU计算的平台.鉴于GPU拥有极其强大的并行运算能力,学习使用Direct