Flux

1、引入:在React的应⽤中,状态管理是⼀个⾮常重要的⼯作。我们不会直接对DOM节点进⾏操作,⽽是通过将数据设置给state,由state来同步UI,这种⽅式有个潜在的问题,每个组件都有独⽴的state,并且不能相互传递。如果从⼀个组件将数据传递给另⼀个组件,需要通过props。⽽props的特点是⾃顶⽽下的传递,那么⼦组件要传递给⽗组件就会⽐较麻烦。当这种需求越来越多后,状态管理就会变得更加困难。

2、定义:它不是⼀种⼯具或框架,⽽是⼀种架构模式。它把所有的数据都集中放在了⼀个叫store的对象中。以后每⼀个组件都不在直接操作state,⽽是把更改数据的命令封装成action,然后dispatch给store。 store再完成state的更改,对应的组件 完成UI更新。

3、核心概念:

   - store:相当于数据中⼼,可以有多个

   - action:操作命令

   - dispatch:分发action的对象

   - view:视图组件

  - 过程:view -> action -> dispatch -> store -> view

Redux

1、Flux的实现,也扩展了自身。它可以用于任何组件化开发中,比较常见用于React中。

  ①核心概念:

     - store:数据中⼼,只有⼀个

     - action:操作命令 - action creator:创建命令的⽅法

     - dispatch:分发action的对象 - middleware:中间件

     - reducer:更新state数据的⽅法

     - view:视图

   ②流程:view -> action creator -> action -> dispatch -> middleware -> reducer -> -> state -> view

   ③reducer必须是1个纯函数,就是函数里的数据没有副作用的,每调用1次函数的结果必须是一致的,且只能操作state,比如函数里做加法,那么就只能做加法,而不能一会儿加法一会儿减法。如果函数里有异步操作,就会改变函数的操作方法,这样就不会纯函数。

2、具体用法: 安装: npm i redux npm i react-redux

  ①编写action creator。 在src下创建actions文件夹,actions下有index.js,用于储存所有的action操作命令。

/src/actions/index.js
export const setVisible = (visible) => {
return {
// type必须写,是命令的名称,必须全大写,中间用_连接
type: 'ADD_TODO',
visible
}
}

  ②编写reducer:在src文件夹下创建reducers文件夹,然后在此文件下建立index.js,用于将所有的更新state数据的方法reducer都合并到一起,然后创建1个componentReducer.js文件存放单一的1个reducer。 将传送过来的值设置到store的state里:

// /src/reducers/componentReducer.js
// 传入第一个参数state,刚开始可能什么都没有,所以给个默认初始值
// 传入第二个参数action,即命令,它包含了传过来的type和state的值。1个命令只改1个属性 export default (state = { visible: false }, action) => {
switch (action.type) { // 我们不直接修改state的值,而是返回1个新的对象,这样在做优化时即便浅比较也会更新。
// 浅比较:赋对象的变量储存的是地址,当我们改属性的值时,变量储存的地址没变,这样浅比较时就认为它是没变化的,从而在优化时不会更新后续组件
// 返回用ES6的扩展运算符,对象里只能有唯一键,相同的会替换。 case "SET_VISIBLE":
return {...state,visible:action.visible}
default:
return state;
}
}

  将多个reducer合并为一个:

// /src/reducers/index.js
// 将所有的更新state数据的方法reducer都合并到一起
import { combineReducers } from 'redux';
import componentReducer from './componentReducer'
import updateStudentReducer from './updateStudentReducer'
export default combineReducers({
componentReducer,
updateStudentReducer
})

  ③将reducer组合到store中:用到react-redux的Provider组件,将其设置成根组件,然后将store设置给它。

// /src/store/index.js
// store主要把reducer结合进来 import React from 'react';
import reducers from '../reducers';
import { Provider } from 'react-redux'
// 创建store
import { createStore} from 'redux'
let store = createStore(reducers) // ⽤到react-redux的Provider组件,将其设置成根组件,然后将store设置给它
export default (props) => {
return <Provider store={store}>
{/* 将入口的组件传进来*/}
{props.children}
</Provider>
}

我们在src下建立了index.js,作为项目的主入口,然后用< Store>将入口装起来,作为所有子组件的根级元素。

// /src/index.js
import React from "react"
import ReactDOM from "react-dom"
import Store from "./antd/store"
import Router from "./router"
// 把store作为所有组件的根组件
ReactDOM.render(<Store><Router /></Store>, document.getElementById("root"));

到这里,我们就把基础配置完成,下面就是如何使用它了。

  ④将组件和redux关联起来:我们先把子组件和redux关联起来,也就是将子组件和store建立联系。在这里我们使用react-redux下的connect方法

import { connect } from "react-redux"
class StudentsList extends Component {
//省略
}
// 关联当前组件StudentsList到store后默认导出。关联之后props里才有dispatch方法
export default connect()(StudentsList)

connect()()方法后置两个圆括号, - 第一个圆括号用于映射,圆括号里可以是一个回调函数,自带1个参数store,它存储着所有的state状态,我们可以直接调用。映射成功了的子组件中,就可以直接通过 props来获取state里的值了。如:this.props.visible就可以获得我存储在store里的visible的值 - 第二个圆括号用于关联,圆括号里写1个要关联的组件名。即将子组件关联到store上。关联之后子组件中的props才能dispatch方法,用于操作命令的分发。如:

import { setVisible } from "../actions"
// 使用dispatch分发action对象到setVisible,并设置值为true,这样就调用了store里面的actions操作命令里的setVisible命令
this.props.dispatch(setVisible(true))

这样我们就可以通过dispatch来分发action命令,从而调用之前我们写的命令setVisible来改变对应state的状态了。

  ⑤异步操作存在问题及解决

  在⼀般情况下,都是发出action后,由reducer完成state的计算,然后更新组件。但是如果遇到 有异步操作怎么办呢?reducer是纯函数,不适合做除设置state以外的其他操作。 action creator的⽅法要求返回的是⼀个命令对象,异步操作在这⾥也有问题。 我们来看1个例子:

// /src/actions/index.js
// 当要发送请求时,因为axios是个异步操作,它会先return,那么返回的student里就没有值,所有在这里要引入中间件thunk
import axios from "axios";
export const setStudent = (id) => {
let student;
axios({
method:"get",
url:"/students/"+id
}).then(({data})=>{
student = data
})
return {
type: 'SET_VISIBLE',
student
}
}

  我用axios发送ajax向服务器请求数据,由于ajax是异步操作,那么return会比student = data(将取回的数据赋值给student)先执行,结果我们就return的student结果只能为undefined。return放到then方法里面也不行,如果放里面就无法说清return是针对哪个地方的了。那么怎么解决呢?

   redux提供了中间件来解决这个问题。我们引入中间件:redux-thunk, 首先我们将前面的store下的index.js进行修改:

// store主要把reducer结合进来

import React from 'react';
import reducers from '../reducers';
import { Provider } from 'react-redux' // 引入异步操作的中间插件redux-thunk。安装:npm i redux-thunk
import thunk from 'redux-thunk'
// 创建store,然后用 applyMiddleware来应用中间插件
import { createStore, applyMiddleware } from 'redux'
let store = createStore(reducers, applyMiddleware(logger,thunk)) // ⽤到react-redux的Provider组件,将其设置成根组件,然后将store设置给它
export default (props) => {
return <Provider store={store}>
{/* 将入口的传进来 */}
{props.children}
</Provider>
}

在这里,引入了中间件thunk,并将这个中间件应用到了reducers里面。 然后我们调用axios来发送异步请求:

// /src/actions/index.js
import axios from "axios";
export const setStudent = (id) => {
return (dispatch, getState) => {
axios({
method: "get",
url:"/students/"+id
}).then(({ data }) => {
//应用中间件后,这里可以使用dispatch来发送action命令更新数据
dispatch({
type: 'SET_STUDENT',
updateStudent: data
});
})
}
}

得到数据后,我们在需要用到的组件里进行映射:

// /src/students/updateStudents.js
export default connect(
// 简化代码 ,箭头函数中的圆括号()就是return的意思
// ({ componentReducer: { visible } }) => ( visible )
// 等同于:
(store) => {
return {
visible: store.componentReducer.visible,
updateStudent:store.updateStudentReducer.updateStudent
}}
)(
Form.create({
// antd里的解决受控组件的方法
//在这里我们就用上面映射回来的值设置到对应的输入框了。
mapPropsToFields(props) {
return {
name: Form.createFormField({
value: props.updateStudent.name
}),
age: Form.createFormField({
value: props.updateStudent.age
}),
gender: Form.createFormField({
value: props.updateStudent.gender
}),
};
}
})(UpdateStudents)
)

  ⑥在这里补充1个使用的中间件logger

logger是一个日志处理的中间件,它会自动打印操作时间的前后值的变化。

其中 prev state的内容为操作前的内容, next state为操作后的内容,这样方便对比。

下载: npm i redux-logger.

使用:

import    {createLogger}    from 'redux-logger';
const logger = createLogger();
let store = createStore(reducers,applyMiddleware(logger))

React初识整理(五)--Redux和Flux(解决状态传递问题)的更多相关文章

  1. React初识整理(一)

    一.React的特点 1.自动化的UI状态管理:自动完成数据变化与界面效果的更新. 2.虚拟DOM:创建1个虚拟的dom节点树,放在内存里(内存修改数据效率高),数据变化时先修改内存里的虚拟DOM,然 ...

  2. React初识整理(三)--受控组件解决方法

    1. 受控组件:组件处于受控制状态,不可更改输入框内的值. 2. 什么情况下会让组件变成受控组件? - 文本框设置了value属性的时候 - 单选框或多选框设置了checked属性的时候. 3. 如何 ...

  3. React初识整理(四)--React Router(路由)

    官网:https://reacttraining.com/react-router 后端路由:主要做路径和方法的匹配,从而从后台获取相应的数据 前端路由:用于路径和组件的匹配,从而实现组件的切换. 如 ...

  4. React初识整理(二)--生命周期的方法

    React生命周期主要有7中: 1. componentWillMount() :组件将要挂载时触发 ,只调用1次 2. componentDidMount() :组件挂载完成时触发,只调用1次 3. ...

  5. 【前端】react学习阶段总结,学习react、react-router与redux的这些事儿

    前言 借用阮一峰的一句话:真正学会 React 是一个漫长的过程. 这句话在我接触react深入以后,更有感触了.整个react体系都是全新的,最初做简单的应用,仅仅使用react-tools打包js ...

  6. 如何在非 React 项目中使用 Redux

    本文作者:胡子大哈 原文链接:https://scriptoj.com/topic/178/如何在非-react-项目中使用-redux 转载请注明出处,保留原文链接和作者信息. 目录 1.前言 2. ...

  7. 【React】360- 完全理解 redux(从零实现一个 redux)

    点击上方"前端自习课"关注,学习起来~ 前言 记得开始接触 react 技术栈的时候,最难理解的地方就是 redux.全是新名词:reducer.store.dispatch.mi ...

  8. 使用react Context+useReducer替代redux

    首先明确一点,Redux 是一个有用的架构,但不是非用不可.事实上,大多数情况,你可以不用它,只用 React 就够了. 曾经有人说过这样一句话. "如果你不知道是否需要 Redux,那就是 ...

  9. 如何优雅地在React项目中使用Redux

    前言 或许你当前的项目还没有到应用Redux的程度,但提前了解一下也没有坏处,本文不会安利大家使用Redux 概念 首先我们会用到哪些框架和工具呢? React UI框架 Redux 状态管理工具,与 ...

随机推荐

  1. [原创]内网渗透专用SSH连接工具sshcmd/sshshell/ssh密码破解以及Kali开启SSH

    目录 1.Kali开启SSH 2.SSH连接工具优缺点 3.渗透专用SSH连接工具 4.ssh执行cmd源码 5.批量SSH密码破解 6.相关工具下载 0x001 SSH配置 1.打开文件 etc/s ...

  2. java简单操作redis数据库

    package RedisTest; import redis.clients.jedis.Jedis; public class RedisTest { private static String ...

  3. [題解] luogu p1220 關路燈

    區間dp 题目描述 某一村庄在一条路线上安装了n盏路灯,每盏灯的功率有大有小(即同一段时间内消耗的电量有多有少).老张就住在这条路中间某一路灯旁,他有一项工作就是每天早上天亮时一盏一盏地关掉这些路灯. ...

  4. 爬虫scrapy框架之CrawlSpider

    爬虫scrapy框架之CrawlSpider   引入 提问:如果想要通过爬虫程序去爬取全站数据的话,有几种实现方法? 方法一:基于Scrapy框架中的Spider的递归爬取进行实现(Request模 ...

  5. Qt 进程和线程之四:线程实际应用

    为了让程序尽快响应用户操作,在开发应用程序时经常会使用到线程.对于耗时操作如果不使用线程,UI界面将会长时间处于停滞状态,这种情况是用户非常不愿意看到的,我们可以用线程来解决这个问题. 大多数情况下, ...

  6. linux进行文件vim编辑时没有退出文件直接关闭出现E325: ATTENTION Found a swap file by the name "/usr/local/php/etc/.php.ini.swp"

    E325: ATTENTIONFound a swap file by the name "/usr/local/php/etc/.php.ini.swp"          ow ...

  7. c#学习系列之字段(静态,常量,只读)

    C#静态变量使用 static 修饰符进行声明,在类被实例化时创建,通过类进行访问不带有 static 修饰符声明的变量称做非静态变量.static变量在对象被实例化时创建,通过对象进行访问一个类的所 ...

  8. java transient关键字作用,使用场景

    transient的作用及使用方法,官方解释为: Variables may be marked transient to indicate that they are not part of the ...

  9. 从零开始利用vue-cli搭建简单音乐网站(二)

    1.利用vue-router实现页面跳转 程序可以正常运行之后,下面我们需要配置路由实现页面的局部刷新,这一功能将用来实现网站页面的跳转. 打开程序目录,进入"src\router\inde ...

  10. Ubuntu16.04 + cuda8.0 + GTX1080安装教程

    1. 安装Ubuntu16.04 不考虑双系统,直接安装 Ubuntu16.04,从 ubuntu官方 下载64位版本: ubuntu-16.04-desktop-amd64.iso . 在MAC下制 ...