1.Redux 设计理念

  Web 应用是一个状态机,视图与状态是一一对应的

  所有的状态,保存在一个对象里面

2.基本概念和API

  Redux 的核心就是 store, action, reducer   store.dispatch(action) ——> reducer(state, action) ——> final state

(1)store 就是保存数据的地方,redux 提供createStore 函数,生成Store

    store = redux.createStore(reducer, []);

store.getState() //返回store的当前状态

  Store 允许使用store.subscribe方法设置监听函数,一旦 State 发生变化,就自动执行这个函数。

  store.subscribe(listener);

  store.subscribe 方法返回一个函数,调用这个函数就可以解除监听

  let unsubscribe = store.subscribe(() =>

    console.log(store.getState())

  );

  unsubscribe(); //解除监听

  Store 的实现

store.getState() //获取当前状态

store.dispatch() //触发action

store.subscribe() //监听state状态

import { createStore } from ‘redux’;

let { subscribe, dispatch, getState } = createStore(reducer, window.STATE_FORM_SERVER);

window.STATE_FORM_SERVER //是整个应用的初始状态值

(2)action 是一个普通的object,必须有一个type属性,表明行为的类型。

  const action = {

    type: ’add_todo’,

    text: ‘read’,

    time

    …

  }

  action描述当前发生的事情,改变State的唯一方法就是通过action,会将数据送到store。

  一般用actionCreator 工厂模式产生,View要发出的消息类型对应action的类型,手写起来很费劲。

  const ADD_TODO = “添加 todo”;

  function addTodo(text){

    return {

     type: ADD_TODO,

      text

}

  }

  const action = addTodo(‘Learn’);

  addTodo 方法就是一个Action Creator

  View 发出Action的唯一途径 store.dispatch(action) //触发事件

(3)reducer 其实就是一个普通函数,主要用来改变state. Store 收到View 发出的Action 以后,必须返回一个新的State,View 才会发生变化。 而这个计算新的State的过程就叫Reducer.

  const reducer = function(state, action){

  switch(state.text){

case ‘add_todo’:

  return state.contact(‘…’);

default:

  return state;

}

  }

  当然实际开发不像上面例子这么简单,需要在创建state的时候就知道state的计算规则,将reducer传入:

  store = redux.createStore(reducer);

  Reducer 纯函数,只要有同样的输入必然返回同样的输出。不能改变原来的state而是通过Reducer返回一个新的state。

//state 是一个对象

function reducer(state, action){

return Object.assign({},state, {thingToChange});

         return {…state, …newState};

}

//state 是一个数组

function reducer(state, action){

return […state, newItem];

}

3.Reducer的拆分和合并

在实际项目中,reducer 很庞大,不易阅读管理,我们可以将reducer 拆分成小的函数,不同的函数对应处理不同的属性。然后将其合并成一个大的reducer

Reducer 提供了一个方法combineReducers方法来合并reducer.

const chatReducer = (state = defaultState, action = {}) => {
return {
chatLog: chatLog(state.chatLog, action),
statusMessage: statusMessage(state.statusMessage, action),
userName: userName(state.userName, action)
}
}; import { combineReducers } from 'redux'; const chatReducer = combineReducers({
chatLog,
statusMessage,
userName
}) export default todoApp;

你可以把所有子reducers 放在一个文件夹里,然后统一引入。

import { combineReducers } from 'redux'

import * as reducers from './reducers'

const reducer = combineReducers(reducers)

4.中间件和异步操作

我们使用redux ,用户发出action,Reducer算出新的state,然后重新渲染界面。这里Reducer是立即算出state,立即响应的,同步执行的顺序。

可是如果我们需要执行异步实现,Reducer执行完之后,自动执行呢? 这里就需要用到middleWare(中间件)。

中间件加在什么地方合适?我们来简单分析下。

1. Reducer 是纯函数,用来计算state,相同的输入必然得到相同的输出,理论上纯函数不允许读写操作。

2. View和state是一一对应,是state的呈现,没有处理能力。

3. Action 是存放数据的对象,即消息的载体,被触发操作。

最后发现,只有加在store.dispatch() 比较合适。添加日志功能,把 Action 和 State 打印出来,可以对store.dispatch进行如下改造。

let next = store.dispatch;
store.dispatch = function dispatchAndLog(action) {
console.log('dispatching', action);
next(action);
console.log('next state', store.getState());
}

总结:中间件其实就是一个函数,对store.dispatch方法进行了改造,在发出 Action 和执行 Reducer 这两步之间,添加了其他功能。

中间件的用法:

const store = createStore(
reducer,
initial_state,
applyMiddleware(logger)
);

createStore方法可以接受整个应用的初始状态作为参数,将中间件(logger)放在applyMiddleware方法之中,传入createStore方法,就完成了store.dispatch()的功能增强。

applyMiddleware 是Redux 的原生方法,作用是将所有中间件组成一个数组,依次执行。下面是它的源码:

export default function applyMiddleware(...middlewares) {
return (createStore) => (reducer, preloadedState, enhancer) => {
var store = createStore(reducer, preloadedState, enhancer);
var dispatch = store.dispatch;
var chain = []; var middlewareAPI = {
getState: store.getState,
dispatch: (action) => dispatch(action)
};
chain = middlewares.map(middleware => middleware(middlewareAPI));
dispatch = compose(...chain)(store.dispatch); return {...store, dispatch}
}
}

可以看到,中间件内部(middlewareAPI)可以拿到getState和dispatch这两个方法。

异步操作的一个解决方案,就是让 Action Creator 返回一个 Promise 对象。看一下redux-promise的源码:

export default function promiseMiddleware({ dispatch }) {
return next => action => {
if (!isFSA(action)) {
return isPromise(action)
? action.then(dispatch)
: next(action);
} return isPromise(action.payload)
? action.payload.then(
result => dispatch({ ...action, payload: result }),
error => {
dispatch({ ...action, payload: error, error: true });
return Promise.reject(error);
}
)
: next(action);
};
}

从上面代码可以看出,如果 Action 本身是一个 Promise,它 resolve 以后的值应该是一个 Action 对象,会被dispatch方法送出(action.then(dispatch)),但 reject 以后不会有任何动作;如果 Action 对象的payload属性是一个 Promise 对象,那么无论 resolve 和 reject,dispatch方法都会发出 Action。

5.React+Redux

redux将所有组件分为UI组件和容器组件。

UI 组件有以下几个特征。

  1. 只负责 UI 的呈现,不带有任何业务逻辑
  2. 没有状态(即不使用this.state这个变量)
  3. 所有数据都由参数(this.props)提供
  4. 不使用任何 Redux 的 API

UI 组件又称为"纯组件",即它纯函数一样,纯粹由参数决定它的值。

容器组件的特征恰恰相反。

  1.负责管理数据和业务逻辑,不负责 UI 的呈现

  2.带有内部状态

  3.使用 Redux 的 API

React-Redux 提供connect方法,用于从 UI 组件生成容器组件。connect的意思,就是将这两种组件连起来。

import { connect } from 'react-redux'

const VisibleTodoList = connect(

mapStateToProps,

mapDispatchToProps

)(TodoList)

上面代码中,connect方法接受两个参数:mapStateToProps和mapDispatchToProps。

它们定义了 UI 组件的业务逻辑。前者负责输入逻辑,即将state映射到 UI 组件的参数(props),后者负责输出逻辑,即将用户对 UI 组件的操作映射成 Action。

6. react+redux 的 simple 示例

原理图:

<div id="container"></div>

<script type="text/babel">

  //工厂Action

    var addTodoAction = function(text){

      return {

        type: 'add_todo',

        text: text

      }

    };

    var todoReducer = function(state,action){

      if(typeof state === 'undefined') return [];

      switch(action.type){

        case 'add_todo':

        return state.slice(0).concat({

          text: action.text,

          completed:false

        });

        default:

        return state;

      }

    };

    var store = redux.createStore(todoReducer);

    var App = React.createClass({

      //获取初始状态

      getInitialState: function(){

        return {

          items: store.getState()

        };

      },

      componentDidMount: function(){

        var unsubscribe = store.subscribe(this.onChange);

      },

      onChange: function(){

        this.setState({

          items: store.getState()

        });

      },

      handleAdd: function(){

        var input = ReactDOM.findDOMNode(this.refs.todo);

        var value = input.value.trim();

        if(value){

          store.dispatch(addTodoAction(value));

        }

        input.value = '';

      },

      render: function(){

        return(

          <div>

          <input ref="todo" type="text" placeholder="input todo type"/>

          <button onClick ={this.handleAdd}>Add</button>

          <ul>

          {

            this.state.items.map(function(item){

              return <li>{item.text}</li>

            })

          }

          </ul>

          </div>

        );

      }

    });

    ReactDOM.render(

      <App />,

      document.getElementById('container')

    )

  </script>

Redux 学习总结的更多相关文章

  1. redux学习

    redux学习: 1.应用只有一个store,用于保存整个应用的所有的状态数据信息,即state,一个state对应一个页面的所需信息 注意:他只负责保存state,接收action, 从store. ...

  2. React Redux学习笔记

    React Router React Router 使用教程 Redux中间件middleware [译]深入浅出Redux中间件 Redux学习之一:何为middleware? ES6 ES6新特性 ...

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

    前言 React+Redux 分为两部分: UI组件:即React组件,也叫用户自定义UI组件,用于渲染DOM 容器组件:即Redux逻辑,处理数据和业务逻辑,支持所有Redux API,参考之前的文 ...

  4. redux学习总结

    redux学习总结 *:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !imp ...

  5. Redux学习及应用

    Redux学习及应用 一:Redux的来源? Redux 是 JavaScript 状态容器,提供可预测化的状态管理.Redux是由 Flux 演变而来,但受 Elm 的启发,避开了 Flux 的复杂 ...

  6. 【原】redux学习笔记

    上周学习了flux,这周研究了一下redux,其实很早之前都已经在研究他们了,只是之前一直没搞懂,最近这两周可能打通了任督二脉,都算入门了. 写博客的目的主要是做一下笔记,总结一下思路,以及和大家交流 ...

  7. react与redux学习资料的整理

    **重点内容**React学习 1.新手入门可以访问react的官方网站,如果英语不是特别好的同学可以访问中文版的,具体链接http://reactjs.cn/react/index.html 首页有 ...

  8. Redux 学习(1) ----- Redux介绍

    Redux 有三个基本的原则: 1,单一状态树,redux 只使用一个javascript 对象来保存整个应用的状态. 状态树样式如下: const state = { count: 0 } 2,状态 ...

  9. Redux学习之解读applyMiddleware源码深入middleware工作机制

    随笔前言 在上一周的学习中,我们熟悉了如何通过redux去管理数据,而在这一节中,我们将一起深入到redux的知识中学习. 首先谈一谈为什么要用到middleware 我们知道在一个简单的数据流场景中 ...

  10. Redux学习day1

    01.React介绍 Redux是一个用来管理管理数据状态和UI状态的JavaScript应用工具.随着JavaScript单页应用(SPA)开发日趋复杂,JavaScript需要管理比任何时候都要多 ...

随机推荐

  1. String 和 StringBuilder

    官方解释 String  String 类代表字符串.字符串是常量:它们的值在创建之后不能更改. StringBuilder 一个可变的字符序列. 疑问 字符串是常量:它们的值在创建之后不能更改.那 ...

  2. if ,while ,for 的掌握

    a)python的缩进和冒号 对于Python而言代码缩进是一种语法,Python没有像其他语言一样采用{}或者begin...end分隔代码块,而是采用代码缩进和冒号来区分代码之间的层次. 缩进的空 ...

  3. IntelliJ IDEA 2018 破解过程[详细步骤](Mac OS & Windows)

    注册码获取地址:http://idea.lanyus.com/ 1.软件下载 首先进入https://www.jetbrains.com官网进行下载. 2.下载破解包 可百度搜索JetbrainsCr ...

  4. 小学生噩梦——四则运算题库(python 全功能实现)

    Github: https://github.com/holidaysss 小组:龙天尧(代码实现),林毓植(浮点转分数函数,代码审查) PSP2.1 Personal Software Proces ...

  5. leetcode 687.Longest Univalue Path

    寻找最长的路径,那么会在左边或者右边或者是从左到跟然后再到右方的路径的. /** * Definition for a binary tree node. * struct TreeNode { * ...

  6. Spring @EventListener 异步中使用condition的问题

    @EventListener是spring在4.2+推出的更好的使用spring事件架构的方式,并且异步方式也很好设定 但是在spring4.2.7版本上使用eventlistener的conditi ...

  7. #20175120彭宇辰-实验一《Java开发环境的熟悉》实验报告

    Java开发环境的熟悉-1 实验要求:1 .建立“自己学号exp1”的目录2 .在“自己学号exp1”目录下建立src,bin等目录3 .javac,java的执行在“自己学号exp1”目录4 .提交 ...

  8. 设计一个字符串类String(C++练习题)

    要求:设计一个字符串类String,可以求字符串长度,可以连接两个串(如,s1=“计算机”,s2=“软件”,s1与s2连接得到“计算机软件”),并且重载“=”运算符进行字符串赋值,编写主程序实现:s1 ...

  9. .net core+Spring Cloud学习之路 二

    前言: 原本计划这次写一下搭建eureka群集.但是发现上次写的只是服务的注册,忘了写服务的发现,所以这次先把服务发现补上去. 我们基于上篇文章,再新建两个.net core web api项目,分别 ...

  10. a链接中 JS弹出确认对话框方法

    一种: <a href="javascript:if(confirm('确实要删除该内容吗?'))location='http://www.google.com'">弹 ...