Redux可以简单概况为:将需要修改的state都存入到store里,发起一个action用来描述发生了什么,用reducers描述action如何改变state tree 。创建store的时候需要传入reducer,真正能改变store中数据的是store.dispatch API。

1. Redux使用场景

  1. 某个组件的状态,需要共享
  2. 不同组件之间通信

2. Redux 特点

2.1 Store

store是一个数据仓库,一个应用中store是唯一的,它里面封装了state状态,当用户想访问state的时候,只能通过store.getState()来取得state对象。

2.2 action

action描述了一个更新state的动作,它是一个对象,其中type属性是必须有的,它指定了某动作和要修改的值:

{
type: CHANGE_INPUT_VALUE,
value: 'abc'
}

2.3 actionCreator

actionCreator 是一个方法,用来创建action对象,调用这个方法就能返回一个action对象,用于简化代码

2.4 dispatch

dispatch 是一个方法,它用于派发一个动作action,这是唯一的一个能够修改state的方法,它内部会调用reducer来调用不同的逻辑基于旧的state来更新出一个新的state。

2.5 reducer

reducer是更新state的核心,它里面封装了更新state的逻辑,reducer由外界提供(封装业务逻辑,在createStore时传入),并传入旧state对象和action,将新值更新到旧的state对象上返回。

3. Redux 三大原则

3.1 单一数据源

整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中。组件通过如下方式取出state中数据:

console.log(store.getState())

3.2 State 是只读的

唯一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象。

store.dispatch({
type: 'CHANGE_INPUT_VALUE',
value: 'abc'
})

3.3 使用纯函数来执行修改 reducers

为了描述 action 如何改变 state tree ,你需要编写 reducers。Reducer 只是一些纯函数,它接收先前的 state 和 action,并返回新的 state。

const defaultState = { // 默认一个state
inputValue: 'abc',
list: [1,2,3]
}; export default (state = defaultState, action) => {
console.log(state, action);
if (action.type === 'CHANGE_INPUT_VALUE') {
let newState = JSON.parse(JSON.stringify(state)); // 深拷贝一份state
newState.inputValue = action.value; // 更改拷贝后的state
return newState; // 将更新后的新的state 返回给 store
}
return state;
}

4 示例应用 - Todolist

入口文件 /src/index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import Todolist from './Todolist'; ReactDOM.render(<Todolist />, document.getElementById('root'));

新建文件 src/Todolist.js

import React, { Component, Fragment } from 'react'; 

class TodoList extends Component {

  render() {
return (
<Fragment>
<div style={{padding: '10px'}}>
todolist
</div>
</Fragment>
)
}
} export default TodoList;

4.1 创建 store

新建目录: /src/store

4.2 store 入口文件

创建文件:/src/store/index.js:

import { createStore } from 'redux'
import reducer from './reducer' const store = createStore(reducer) export default store

4.3 统一定义action.type

新建文件:/src/store/actionType.js,

export const CHANGE_INPUT_VALUE = 'change_input_value';  // 更改input处输入框里面的值
export const ADD_TOTO_ITEM = 'add_todo_item'; // 添加待办事项
export const DELETE_TODO_ITEM = 'detete_todo_item'; // 删除待办事项

4.4 创建action对象

新建文件:/src/store/actionCreator.js

// 引入 actionType 模块
import {
CHANGE_INPUT_VALUE,
ADD_TOTO_ITEM,
DELETE_TODO_ITEM,
} from './actionType' // 更改input处输入框里面的值
export const getInputChangeAction = (value) => {
return {
type: CHANGE_INPUT_VALUE,
value
}
} // 添加待办事项
export const getAddItemAction = () => {
return {
type: ADD_TOTO_ITEM
}
} // 删除待办事项
export const getDeleteItemAction = (index) => {
return {
type: DELETE_TODO_ITEM,
index
}
}

4.5 reducer 更新 state

新建文件:/src/store/reducer.js

import {
CHANGE_INPUT_VALUE,
ADD_TOTO_ITEM,
DELETE_TODO_ITEM,
} from './actionType' const defaultState = { // 默认一个state
inputValue: 'abc',
list: [1,2,3]
}; // 注意:reducer 可以接收state, 但是不允许修改state,所以需要深拷贝一份state
export default (state = defaultState, action) => {
console.log(state, action);
if (action.type === CHANGE_INPUT_VALUE) {
let newState = JSON.parse(JSON.stringify(state)); // 深拷贝一份state
newState.inputValue = action.value; // 更改拷贝后的state
return newState; // 将更新后的新的state 返回给 store
}
if (action.type === ADD_TOTO_ITEM) {
let newState = JSON.parse(JSON.stringify(state));
newState.list.push(newState.inputValue);
newState.inputValue = '';
return newState;
}
if (action.type === DELETE_TODO_ITEM) {
let newState = JSON.parse(JSON.stringify(state));
newState.list.splice(action.index, 1); // 删除当前index的item
return newState;
}
return state;
}

4.6 修改 src/Todolist.js

import React, { Component, Fragment } from 'react';
import "antd/dist/antd.css";
import { Input, Button, List } from 'antd';
import store from './store/index';
import { getInputChangeAction, getAddItemAction, getDeleteItemAction } from './store/actionCreators'; class TodoList extends Component { constructor(props) {
super(props); this.state = store.getState(); this.handleInputChange = this.handleInputChange.bind(this);
this.handleBtnClick = this.handleBtnClick.bind(this); this.handleStoreChange = this.handleStoreChange.bind(this);
// 订阅store,只要store中state有变化,就执行handleStoreState函数
store.subscribe(this.handleStoreChange);
} handleInputChange (e) {
const action = getInputChangeAction(e.target.value); // 将需要执行的action传给store
store.dispatch(action);
} handleBtnClick () {
const action = getAddItemAction();
store.dispatch(action);
} handleItemDelete (index) {
const action = getDeleteItemAction(index);
store.dispatch(action);
} handleStoreChange () {
// 当store中state变化时,则重新取一次数据进行替换
this.setState(store.getState());
} render() {
return (
<Fragment>
<div style={{padding: '10px'}}>
<div>
<Input
value={this.state.inputValue}
placeholder="input something"
style={{width: '300px',marginRight: '10px'}}
onChange={this.handleInputChange}
/>
<Button type="primary" onClick={this.handleBtnClick}>提交</Button>
</div>
<List
style={{marginTop: '10px', width: '300px'}}
bordered
dataSource={this.state.list}
renderItem={
(item, index) => <List.Item onClick={this.handleItemDelete.bind(this, index)}>{item}</List.Item>
}
/>
</div>
</Fragment>
)
}
} export default TodoList;

5 项目目录

React 之 Redux 的使用的更多相关文章

  1. 实例讲解react+react-router+redux

    前言 总括: 本文采用react+redux+react-router+less+es6+webpack,以实现一个简易备忘录(todolist)为例尽可能全面的讲述使用react全家桶实现一个完整应 ...

  2. 基于 React.js + Redux + Bootstrap 的 Ruby China 示例 (转)

    一直学 REACT + METEOR 但路由部分有点问题,参考一下:基于 React.js + Redux + Bootstrap 的 Ruby China 示例 http://react-china ...

  3. 基于react+react-router+redux+socket.io+koa开发一个聊天室

    最近练手开发了一个项目,是一个聊天室应用.项目虽不大,但是使用到了react, react-router, redux, socket.io,后端开发使用了koa,算是一个比较综合性的案例,很多概念和 ...

  4. 最新的chart 聊天功能( webpack2 + react + router + redux + scss + nodejs + express + mysql + es6/7)

    请表明转载链接: 我是一个喜欢捣腾的人,没事总喜欢学点新东西,可能现在用不到,但是不保证下一刻用不到. 我一直从事的是依赖angular.js 的web开发,但是我怎么能一直用它呢?看看最近火的一塌糊 ...

  5. 【前端】react and redux教程学习实践,浅显易懂的实践学习方法。

    前言 前几天,我在博文[前端]一步一步使用webpack+react+scss脚手架重构项目 中搭建了一个react开发环境.然而在实际的开发过程中,或者是在对源码的理解中,感受到react中用的最多 ...

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

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

  7. [React] 14 - Redux: Redux Saga

    Ref: Build Real App with React #14: Redux Saga Ref: 聊一聊 redux 异步流之 redux-saga  [入门] Ref: 从redux-thun ...

  8. [React] 15 - Redux: practice IM

    本篇属于私人笔记. client 引导部分 一.assets: 音频,图片,字体 ├── assets │ ├── audios │ ├── fonts │ └── images 二.main&quo ...

  9. react脚手架改造(react/react-router/redux/eslint/karam/immutable/es6/webpack/Redux DevTools)

    公司突然组织需要重新搭建一个基于node的论坛系统,前端采用react,上网找了一些脚手架,或多或少不能满足自己的需求,最终在基于YeoMan的react脚手架generator-react-webp ...

  10. React 与 Redux 在生产环境中的实践总结

    React 与 Redux 在生产环境中的实践总结 前段时间使用 React 与 Redux 重构了我们360netlab 的 开放数据平台.现将其中一些技术实践经验总结如下: Universal 渲 ...

随机推荐

  1. python--协程知识初识

    线程和进程的操作是由程序触发系统接口,最后的执行者是系统:协程的操作则是程序员. 协程存在的意义:对于多线程应用,CPU通过切片的方式来切换线程间的执行,线程切换时需要耗时(保存状态,下次继续).协程 ...

  2. Q1094

    一,看题 1,字符串确实是我的弱项. 2, 二,看题解 #include<iostream> #include<string> using namespace std; int ...

  3. 八大排序算法总结与java实现(转)

    八大排序算法总结与Java实现 原文链接: 八大排序算法总结与java实现 - iTimeTraveler 概述 直接插入排序 希尔排序 简单选择排序 堆排序 冒泡排序 快速排序 归并排序 基数排序 ...

  4. PATA1055 The World's Richest (25 分)

    1055 The World's Richest (25 分) Forbes magazine publishes every year its list of billionaires based ...

  5. Vue中的v-bind指令

    普通: property="value" 此时 value为字符串 v-bind指令 v-bind:property="value" 此时 value会被解析成 ...

  6. 趣谈Linux操作系统学习笔记:第二十七讲

    一.文件系统的功能规划 1.引子 咱们花了这么长的时间,规划了会议室管理系统,这样多个项目执行的时候,隔离性可以得到保证. 但是,会议室里面被回收,会议室里面的资料就丢失了.有一些资料我们希望项目结束 ...

  7. PR代码提交规范

    1.在提交pull request之前,先要把 master上面的合并到 这个分支上面,看看是不是有冲突,然后在提交pr

  8. Java8 流式 API(`java.util.stream`)

    熟悉 ES6 的开发者,肯定对数组的一些方法不是很陌生:map.filter 等.在对一组对象进行统一操作时,利用这些方法写出来的代码比常规的迭代代码更加的简练.在 C♯ 中,有 LINQ 来实现.那 ...

  9. Python的WEB框架

    Python的WEB框架 Bottle Bottle是一个快速.简洁.轻量级的基于WSIG的微型Web框架,此框架只由一个 .py 文件,除了Python的标准库外,其不依赖任何其他模块. ? 1 2 ...

  10. Effective.Java第78-90条(同步相关)

    78.  同步访问共享的可变数据 为了在线程之间进行可靠的通信,也为了互斥访问,同步是必要的. 不共享可变的数据.要么共享不可变的数据,要么压根不共享.换句话说,将可变数据限制在单线程中. 当多个线程 ...