今天,我们要讲解的是异步、单一state树结构、componentWillReceiveProps这三个知识点。

例子

这个例子是官方的例子,主要是从Reddit中请求新闻列表来显示,可以切换react和frontend关键词来切换新闻列表,可以刷新当前新闻列表。

源代码:

https://github.com/lewis617/react-redux-tutorial/tree/master/redux-examples/async

异步

异步本身 这个概念,本文不详细叙述,但可以简单说一下,javascript是通过自身的“事件循环(event loop)”机制来实现异步的,将耗时的IO等操作跳过,当事件完成后再发个信号过来执行回调。这使得单线程的js变的非常高效,这也是为什么 nodejs在多并发场景下特别牛逼的原因。

redux只能实现同步操作,但是可以通过thunk中间件实现异步。thunk的作用看react+redux教程(一)connect、applyMiddleware、thunk、webpackHotMiddleware

主要的异步操作(ajax请求)均在action中进行。

本例子的异步操作在fetchPosts中,就是使用fetch这个第三方包,进行ajax请求,然后使用promise进行完成后的回调操作。看代码:

actions/index.js

import fetch from 'isomorphic-fetch'

export const REQUEST_POSTS = 'REQUEST_POSTS'
export const RECEIVE_POSTS = 'RECEIVE_POSTS'
export const SELECT_REDDIT = 'SELECT_REDDIT'
export const INVALIDATE_REDDIT = 'INVALIDATE_REDDIT'
//选择新闻类型action
export function selectReddit(reddit) {
  return {
    type: SELECT_REDDIT,
    reddit
  }
}
//废弃新闻类型action
export function invalidateReddit(reddit) {
  return {
    type: INVALIDATE_REDDIT,
    reddit
  }
}
//开始获取新闻action
function requestPosts(reddit) {
  return {
    type: REQUEST_POSTS,
    reddit
  }
}
//获取新闻成功的action
function receivePosts(reddit, json) {
  return {
    type: RECEIVE_POSTS,
    reddit: reddit,
    posts: json.data.children.map(child => child.data),
    receivedAt: Date.now()
  }
}

//获取文章,先触发requestPosts开始获取action,完成后触发receivePosts获取成功的action
function fetchPosts(reddit) {
  return dispatch => {
    dispatch(requestPosts(reddit))
    return fetch(`https://www.reddit.com/r/${reddit}.json`)
      .then(response => response.json())
      .then(json => dispatch(receivePosts(reddit, json)))
  }
}

//是否需要获取文章
function shouldFetchPosts(state, reddit) {
  const posts = state.postsByReddit[reddit]
  if (!posts) {
    return true
  }
  if (posts.isFetching) {
    return false
  }
  return posts.didInvalidate
}

//如果需要则开始获取文章
export function fetchPostsIfNeeded(reddit) {
  return (dispatch, getState) => {
    if (shouldFetchPosts(getState(), reddit)) {
      return dispatch(fetchPosts(reddit))
    }
  }
}

异步这个概念比较简单,不再赘述了。

单一state树结构

单一state树结构是redux的最大特点。我们今天主要讲解state的树结构长什么样?首先,我们可以通过react的chrome插件,来看下这个state树:

我们点击Connect(App),可以查看整个程序的state树,但是这棵树是从storeState开始的。我们在第一课中讲到,只能通过redux的devtools来查看全局单一state,其实是片面的,通过react的chrome插件同样可以看到这棵树。

那么这棵树为什么长这个样子,我们是如何构建这棵树的呢?答案都在reducer里面:

reducers/index.js

import { combineReducers } from 'redux'
import {
  SELECT_REDDIT, INVALIDATE_REDDIT,
  REQUEST_POSTS, RECEIVE_POSTS
} from '../actions'

//选择新闻后,将state.selectedReddit设为所选选项
function selectedReddit(state = 'reactjs', action) {
  switch (action.type) {
    case SELECT_REDDIT:
      return action.reddit
    default:
      return state
  }
}

function posts(state = {
  //是否正在获取最新
  isFetching: false,
  //是否废弃
  didInvalidate: false,
  //内容
  items: []
}, action) {
  switch (action.type) {
    case INVALIDATE_REDDIT:
      return Object.assign({}, state, {
        didInvalidate: true
      })
    case REQUEST_POSTS:
      return Object.assign({}, state, {
        isFetching: true,
        didInvalidate: false
      })
    case RECEIVE_POSTS:
      return Object.assign({}, state, {
        isFetching: false,
        didInvalidate: false,
        items: action.posts,
        lastUpdated: action.receivedAt
      })
    default:
      return state
  }
}
//废弃、接收到、开始接受新闻后,将state.postsByReddit设为相关参数
function postsByReddit(state = { }, action) {
  switch (action.type) {
    case INVALIDATE_REDDIT:
    case RECEIVE_POSTS:
    case REQUEST_POSTS:
      return Object.assign({}, state, {
        [action.reddit]: posts(state[action.reddit], action)
      })
    default:
      return state
  }
}
//将两个reducer合并成一个reducer,也就将全局的state加上postsByReddit,selectedReddit两个属性,每个属性都有自己的state
const rootReducer = combineReducers({
  postsByReddit,
  selectedReddit
})

export default rootReducer

我们写了两个reducer,postsByReddit, selectedReddit,最后把它们合并起来。所以我们的全局单一state树的第一级节点是postsByReddit, selectedReddit。

postsByReddit节点下面就是postsByReddit返回的state,也就是[action.reddit]: posts(state[action.reddit], action)。posts()就是{ isFetching: false,didInvalidate: false, items: [] }

现在明白了全局单一state树是如何构建了的吧?----通过reducer。

componentWillReceiveProps

这是react组件生命周期里面的一个时间节点的回调函数。通常在组件接收新的props时触发。我们在componentDidMount()和componentWillReceiveProps()这两个回调里面加上console.log,来追踪这两个事件的触发:

containers/App.js(部分代码)

//初始化渲染后触发
  componentDidMount() {
    console.log('执行componentDidMount');
    const { dispatch, selectedReddit } = this.props
    dispatch(fetchPostsIfNeeded(selectedReddit))
  }

  //每次接受新的props触发
  componentWillReceiveProps(nextProps) {
    console.log('执行componentWillReceiveProps',nextProps);
    if (nextProps.selectedReddit !== this.props.selectedReddit) {
      const { dispatch, selectedReddit } = nextProps
      dispatch(fetchPostsIfNeeded(selectedReddit))
    }
  }

然后我们打开浏览器,执行下面的用户操作,查看console里面的打印信息:

1,刷新页面:

首先,执行了componentDidMount,也就是渲染了组件。然后执行request_post的action,这个action改变了state,state和props就是部分绑定关系,所以触发了componentWillReceiveProps。

然后那个[HMR]是热替换的意思,这里不详细叙述。

接下来又执行了componentWillReceiveProps,为什么呢?因为获取新闻数据成功了,state改变了,被绑定的props也变了,所以执行了componentWillReceiveProps。我们可以看到posts里面已经有值了,这时触发了receive_posts的action。

2,切换新闻类型

切换下拉框,触发了select_reddit的action,改变了state,改变了被绑定的props,所以触发了componentWillReceiveProps

componentWillReceiveProps的回调又触发了request_posts的action,自己看代码。这个action改变了state,改变了被绑定的props,所以又触发了componentWillReceiveProps。

获取新闻数据成功后,又改变了state,改变了被绑定的props,又触发了componentWillReceiveProps,也触发了receive_posts这个action。

3,点击刷新按钮

首先,触发了invalidate_reddit废弃新闻的action,然后触发了request_posts的action,state的isFetching被改变了,所以触发了一次componentWillReceiveProps

接受完成,又触发一次componentWillReceiveProps。

由此可见,componentWillReceiveProps在redux+react的程序中,是个非常常用的概念,甚至可以说,只要能监听每次的componentWillReceiveProps,就可以清楚的了解react和redux的交互过程。


教程源代码及目录

如果您觉得本博客教程帮到了您,就赏颗星吧!

https://github.com/lewis617/react-redux-tutorial

react+redux教程(五)异步、单一state树结构、componentWillReceiveProps的更多相关文章

  1. react+redux教程(二)redux的单一状态树完全替代了react的状态机?

    上篇react+redux教程,我们讲解了官方计数器的代码实现,react+redux教程(一).我们发现我们没有用到react组件本身的state,而是通过props来导入数据和操作的. 我们知道r ...

  2. react+redux教程(四)undo、devtools、router

    上节课,我们介绍了一些es6的新语法:react+redux教程(三)reduce().filter().map().some().every()....展开属性 今天我们通过解读redux-undo ...

  3. react+redux教程(六)redux服务端渲染流程

    今天,我们要讲解的是react+redux服务端渲染.个人认为,react击败angular的真正“杀手锏”就是服务端渲染.我们为什么要实现服务端渲染,主要是为了SEO. 例子 例子仍然是官方的计数器 ...

  4. react+redux教程(三)reduce()、filter()、map()、some()、every()、...展开属性

    reduce().filter().map().some().every()....展开属性   这些概念属于es5.es6中的语法,跟react+redux并没有什么联系,我们直接在https:// ...

  5. react+redux教程(一)connect、applyMiddleware、thunk、webpackHotMiddleware

    今天,我们通过解读官方示例代码(counter)的方式来学习react+redux. 例子 这个例子是官方的例子,计数器程序.前两个按钮是加减,第三个是如果当前数字是奇数则加一,第四个按钮是异步加一( ...

  6. react+redux教程(八)连接数据库的redux程序

    前面所有的教程都是解读官方的示例代码,是时候我们自己写个连接数据库的redux程序了! 例子 这个例子代码,是我自己写的程序,一个非常简单的todo,但是包含了redux插件的用法,中间件的用法,连接 ...

  7. react+redux教程(七)自定义redux中间件

    今天,我们要讲解的是自定义redux中间件这个知识点.本节内容非常抽象,特别是中间件的定义原理,那多层的函数嵌套和串联,需要极强逻辑思维能力才能完全消化吸收.不过我会多罗嗦几句,所以不用担心. 例子 ...

  8. react/redux组件库、模板、学习教程

    开源的有蚂蚁金服的: 1.https://pro.ant.design/index-cn 2.https://pro.ant.design/docs/getting-started-cn 3.http ...

  9. 【前端,干货】react and redux教程学习实践(二)。

    前言 这篇博文接 [前端]react and redux教程学习实践,浅显易懂的实践学习方法. ,上一篇简略的做了一个redux的初级demo,今天深入的学习了一些新的.有用的,可以在生产项目中使用的 ...

随机推荐

  1. 深入浅出Redis-redis底层数据结构(上)

    1.概述 相信使用过Redis 的各位同学都很清楚,Redis 是一个基于键值对(key-value)的分布式存储系统,与Memcached类似,却优于Memcached的一个高性能的key-valu ...

  2. Linux CentOS 配置JDK环境

    一.下载JDK 下载JDK的方式有两种: 1.Linux中使用wget下载 1.使用命令安装wget yum install wget 2.下载 wget 'http://download.oracl ...

  3. 重撸JS_1

    1.声明 用 var 或 let 声明的未赋初值的变量,值会被设定为undefined(译注:即未定义值,本身也是一个值) 试图访问一个未初始化的变量会导致一个 ReferenceError 异常被抛 ...

  4. git-2.10.2-64-bit介绍&&git下载&&git安装教程

    Git介绍 分布式:Git系统是一个分布式的系统,是用来保存工程源代码历史状态的命令行工具. 保存点:Git的保存点可以追踪源码中的文件, 并能得到某一个时间点上的整个工程项目的状态:可以在该保存点将 ...

  5. 脑洞大开之采用HTML5+SignalR2.0(.Net)实现原生Web视频

    目录 对SignalR不了解的人可以直接移步下面的目录 SignalR系列目录 前言 - -,我又来了,今天废话不多说,我们直接来实现Web视频聊天. 采用的技术如下: HTML5 WebRTC Si ...

  6. python 数据类型 ----字典

    字典由一对key:value 组成的 python中常用且重量级的数据类型 1. key , keys, values 字典由一对key:value 组成的 python中常用且重量级的数据类型 1. ...

  7. Flyweight(享元模式)

    import java.util.Hashtable; /** * 享元模式 * @author TMAC-J * 享元模式一般和工厂模式一起使用,但此处为了更好说明,只用享元模式 * 定义:享元模式 ...

  8. gRPC源码分析1-SSL/TLS

    引子 前几天看到微信后台团队分享了TLS相关文章,正好gRPC里TLS数据加密是很重要的一块,于是整理出了这篇文章. 在gRPC里,如果仅仅是用来做后端微服务,可以考虑不加密.本文太长,先给个大纲. ...

  9. Javascript学习笔记

    Javascript 2016年12月19日整理 JS基础 Chapter1 JS是一门运行在浏览器客户端的脚本编程语言,前台语言 组成部分 1. ECMAscript JS标准 2. DOM 通过J ...

  10. BPM费控管理解决方案分享

    一.方案概述费用是除经营成本外企业的最主要支出,费用管理是财务管理的核心之一,加强企业内控管理如:费用申请.费用报销.费用分摊.费用审批.费用控制和费用支付等,通过科学有效的管理方法规范企业费用管理, ...