文章目录

  • ​​1. redux理解​​
  • ​​1.1. 相关文档​​
  • ​​1.2. redux是什么​​
  • ​​1.3. 什么情况下需要使用redux​​
  • ​​1.4. redux工作流程​​
  • ​​2. redux的三个核心概念​​
  • ​​2.1. `action`​​
  • ​​2.2. `reducer`​​
  • ​​2.3. `store`​​
  • ​​3. API​​
  • ​​3.1. `createStore()`​​
  • ​​3.2. store对象​​
  • ​​3.3. `applyMiddleware()`​​
  • ​​3.4. `combineReducers()`​​
  • ​​4. 使用redux编写应用​​
  • ​​4.1 效果​​
  • ​​4.2 实现​​
  • ​​4.2.0 只用react写​​
  • ​​4.2.1 redux精简版​​
  • ​​4.2.2 redux完整版​​
  • ​​4.2.3 redux异步action版 使用异步中间件 redux-thunk​​
  • ​​redux版完整code​​
  • ​​5. react-redux​​
  • ​​5.1. 理解​​
  • ​​5.2. react-redux将所有组件分成两大类​​
  • ​​【补充】函数柯里化​​
  • ​​5.3 基本使用​​
  • ​​5.3.0 连接容器组件和UI组件​​
  • ​​5.3.1 使用 分析:​​
  • ​​5.3.2 整理版​​
  • ​​总结:​​
  • ​​5.4 优化​​
  • ​​优化1 简写mapDispatchToProps​​
  • ​​优化2 Provider​​
  • ​​优化3 整合UI组件和容器组件​​
  • ​​总结:​​
  • ​​优化版完整代码​​
  • ​​5.5 数据共享版​​
  • ​​code图示:​​
  • ​​总结:​​
  • ​​6. 使用上redux调试工具​​
  • ​​6.1 安装chrome浏览器插件​​
  • ​​6.2 下载工具依赖包​​
  • ​​7. 纯函数和高阶函数​​
  • ​​7.1 纯函数​​
  • ​​7.2 高阶函数​​
  • ​​8. 最终版 简写版​​
  • ​​code图示版​​
  • ​​code代码版​​
  • ​​index.jsx​​
  • ​​App.js​​
  • ​​containers/Count/index.jsx​​
  • ​​containers/Person/index.jsx​​
  • ​​src/redux/constant.js​​
  • ​​redux/actions/count.js​​
  • ​​redux/action/person.js​​
  • ​​redux/reducers/index.js​​
  • ​​redux/reducers/count.js​​
  • ​​redux/reducers/person.js​​
  • ​​src/redux/store.js​​
  • ​​效果​​
  • ​​9. 项目运行打包​​

1. redux理解

1.1. 相关文档

中文文档: http://www.redux.org.cn/

Github: https://github.com/reactjs/redux

先把它装上

npm i redux

1.2. redux是什么

  1. redux是一个专门用于做状态管理的JS库(不是react插件库)。
  2. 可以用在react, angular, vue等项目中, 但基本与react配合使用。
  3. 作用: 集中式管理react应用中多个组件共享的状态。

1.3. 什么情况下需要使用redux

  1. 某个组件的状态,需要让其他组件可以随时拿到(共享)
  2. 一个组件需要改变另一个组件的状态(通信)
  3. 总体原则:能不用就不用, 如果不用比较吃力才考虑使用

1.4. redux工作流程

[react] redux react-redux_前端

2. redux的三个核心概念

2.1. ​​action​

  1. 动作的对象
  2. 包含 2 个属性
  1. ​type​​:标识属性, 值为字符串, 唯一, 必要属性
  2. ​data​​:数据属性, 值类型任意, 可选属性
  1. 例子:​​{ type: 'ADD_STUDENT',data:{name: 'tom',age:18} }​

2.2. ​​reducer​

  1. 用于初始化状态、加工状态。
  2. 加工时,根据旧的state和action, 产生新的state的纯函数。

2.3. ​​store​

  1. 将​​state、action、reducer​​联系在一起的对象
  2. 如何得到此对象?
import {createStore} from 'redux'
import reducer from './reducers'
const store = createStore(reducer)
  1. 此对象的功能?
  1. ​getState()​​: 得到state
  2. ​dispatch(action)​​: 分发action, 触发reducer调用, 产生新的state
  3. ​subscribe(listener)​​: 注册监听, 当产生了新的state时, 自动调用

3. API

3.1. ​​createStore()​

作用:创建包含指定​​reducer​​​的​​store​​对象

3.2. store对象

  1. 作用: redux库最核心的管理对象
  2. 它内部维护着:
  1. ​state​
  2. ​reducer​
  1. 核心方法:
  1. ​getState()​
  2. ​dispatch(action)​
  3. ​subscribe(listener)​
  1. 具体编码:
  1. ​store.getState()​
  2. ​store.dispatch({type:'INCREMENT', number})​
  3. ​store.subscribe(render)​

3.3. ​​applyMiddleware()​

作用:应用上基于redux的中间件(插件库)

3.4. ​​combineReducers()​

作用:合并多个reducer函数

4. 使用redux编写应用

4.1 效果

[react] redux react-redux_UI_02

4.2 实现

4.2.0 只用react写

[react] redux react-redux_UI_03

App.jsx

[react] redux react-redux_react.js_04

components/Count/index.jsx

[react] redux react-redux_App_05

[react] redux react-redux_javascript_06

4.2.1 redux精简版

[react] redux react-redux_UI_07

初始值分析:

[react] redux react-redux_App_08

count_reducer.js

[react] redux react-redux_App_09

[react] redux react-redux_javascript_10

完整代码:
(1).去除Count组件自身的状态
(2).src下建立:

  • ​redux​
  • ​store.js​
  • ​count_reducer.js​

(3).store.js:
1).引入​​​redux​​​中的​​createStore​​​函数,创建一个​​store​​​ 2).​​createStore​​调用时要传入一个为其服务的​​reducer​​ 3).记得暴露​​store​​对象

(4).count_reducer.js:
1).​​​reducer​​​的本质是一个函数,接收:​​preState,action​​​,返回加工后的状态
2).​​​reducer​​​有两个作用:初始化状态,加工状态
3).​​​reducer​​​被第一次调用时,是​​store​​​自动触发的,
传递的​​​preState​​​是​​undefined​​​,
传递的​​​action​​​是:​​{type:'@@REDUX/INIT_a.2.b.4}​

(5).在index.js中监测store中状态的改变,一旦发生改变重新渲染​​<App/>​

备注:​​redux​​只负责管理状态,至于状态的改变驱动着页面的展示,要靠我们自己写。

[react] redux react-redux_react.js_11


在index.js中监测store中状态的改变,一旦发生改变重新渲染​​<App/>​

[react] redux react-redux_UI_12


App.jsx

[react] redux react-redux_前端_13

src\redux\store.js

1). 引入​​redux​​​中的​​createStore​​​函数,创建一个​​store​​​ 2). ​​createStore​​调用时要传入一个为其服务的​​reducer​

3). 记得暴露​​store​​对象

[react] redux react-redux_App_14


src\redux\count_reducer.js

1). ​​reducer​​的本质是一个函数,接收:​​preState,action​​,返回加工后的状态

2). ​​reducer​​有两个作用:初始化状态,加工状态

3). ​​reducer​​被第一次调用时,是​​store​​自动触发的,

传递的​​preState​​是​​undefined​​,

传递的​​action​​是:​​{type:'@@REDUX/INIT_a.2.b.4}​

[react] redux react-redux_App_15

src\components\Count\index.jsx

[react] redux react-redux_react.js_16


[react] redux react-redux_javascript_17

4.2.2 redux完整版

完整版新增文件:

count_action.js 专门用于创建action对象
constant.js 放置容易写错的type值

小知识点:

const a=()={
return {data:b}
}

简写:

[react] redux react-redux_App_18

[react] redux react-redux_react.js_19

简写:

[react] redux react-redux_UI_20

完整代码

[react] redux react-redux_UI_21


src\index.js

[react] redux react-redux_前端_22


src\App.jsx

[react] redux react-redux_App_23


src\redux\constant.js

[react] redux react-redux_前端_24


src\redux\count_action.js

[react] redux react-redux_javascript_25

src\redux\count_reducer.js

[react] redux react-redux_UI_26

src\redux\store.js

[react] redux react-redux_javascript_27


src\components\Count\index.jsx

[react] redux react-redux_UI_28


[react] redux react-redux_UI_29


[react] redux react-redux_react.js_30

4.2.3 redux异步action版 使用异步中间件 redux-thunk

(1).明确:延迟的动作不想交给组件自身,想交给action

(2).何时需要异步​​action​​:想要对状态进行操作,但是具体的数据靠异步任务返回。

(3).具体编码:

  • 1).使用异步中间件​​yarn add redux-thunk​​​,并配置在​​store​​中
  • 2).创建​​action​​的函数不再返回一般对象,而是一个函数,该函数中写异步任务。
  • 3).异步任务有结果后,分发一个同步的action去真正操作数据。

(4).备注:异步​​action​​​不是必须要写的,完全可以自己等待异步任务的结果了再去分发同步​​action​​。

小注意点:

[react] redux react-redux_javascript_31

[react] redux react-redux_UI_32

完整代码:
src\index.js

[react] redux react-redux_前端_33


src\App.jsx

[react] redux react-redux_UI_34


src\redux\constant.js

[react] redux react-redux_前端_35

src\redux\count_action.js

[react] redux react-redux_javascript_36


src\redux\count_reducer.js

[react] redux react-redux_App_37


src\redux\store.js

[react] redux react-redux_react.js_38

src\components\Count\index.jsx

[react] redux react-redux_react.js_39

[react] redux react-redux_javascript_40

redux版完整code

[react] redux react-redux_前端_41

src\index.js

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import store from './redux/store'

ReactDOM.render(<App/>,document.getElementById('root'))

store.subscribe(()=>{
ReactDOM.render(<App/>,document.getElementById('root'))
})

APP.js

import React, { Component } from 'react'
import Count from './components/Count'

export default class App extends Component {
render() {
return (
<div>
<Count/>
</div>
)
}
}

constant.js

/* 
该模块是用于定义action对象中type类型的常量值,
目的只有一个:便于管理的同时防止程序员单词写错
*/
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'

count_action.js

/* 
该文件专门为Count组件生成action对象
*/
import {INCREMENT,DECREMENT} from './constant'

//同步action,就是指action的值为Object类型的一般对象
export const createIncrementAction = data => ({type:INCREMENT,data})
export const createDecrementAction = data => ({type:DECREMENT,data})

//异步action,就是指action的值为函数,异步action中一般都会调用同步action,
// 异步action不是必须要用的。
export const createIncrementAsyncAction = (data,time) => {
return (dispatch)=>{
setTimeout(()=>{
dispatch(createIncrementAction(data))
},time)
}
}

count_reducer.js

/* 
1.该文件是用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数
2.reducer函数会接到两个参数,分别为:之前的状态(preState),动作对象(action)
*/
import {INCREMENT,DECREMENT} from './constant'

const initState = 0 //初始化状态
export default function countReducer(preState=initState,action){
// console.log(preState);

//从action对象中获取:type、data
const {type,data} = action

//根据type决定如何加工数据
switch (type) {
case INCREMENT: //如果是加
return preState + data
case DECREMENT: //若果是减
return preState - data
default:
return preState
}
}

store.js

/* 
该文件专门用于暴露一个store对象,整个应用只有一个store对象
*/

//引入createStore,专门用于创建redux中最为核心的store对象
import {
createStore,
applyMiddleware
} from 'redux'

//引入为Count组件服务的reducer
import countReducer from './count_reducer'

//引入redux-thunk,用于支持异步action
import thunk from 'redux-thunk'

//暴露store
export default createStore(countReducer, applyMiddleware(thunk))

src\components\Count\index.jsx

import React, { Component } from 'react'
//引入store,用于获取redux中保存状态
import store from '../../redux/store'
//引入actionCreator,专门用于创建action对象
import {
createIncrementAction,
createDecrementAction,
createIncrementAsyncAction
} from '../../redux/count_action'

export default class Count extends Component {

state = {carName:'奔驰c63'}

//加法
increment = ()=>{
const {value} = this.selectNumber
store.dispatch(createIncrementAction(value*1))
}
//减法
decrement = ()=>{
const {value} = this.selectNumber
store.dispatch(createDecrementAction(value*1))
}
//奇数再加
incrementIfOdd = ()=>{
const {value} = this.selectNumber
const count = store.getState()
if(count % 2 !== 0){
store.dispatch(createIncrementAction(value*1))
}
}
//异步加
incrementAsync = ()=>{
const {value} = this.selectNumber
// setTimeout(()=>{
store.dispatch(createIncrementAsyncAction(value*1,500))
// },500)
}

render() {
return (
<div>
<h1>当前求和为:{store.getState()}</h1>
<select ref={c => this.selectNumber = c}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select> 
<button onClick={this.increment}>+</button> 
<button onClick={this.decrement}>-</button> 
<button onClick={this.incrementIfOdd}>当前求和为奇数再加</button> 
<button onClick={this.incrementAsync}>异步加</button> 
</div>
)
}
}

5. react-redux

5.1. 理解

一个React插件库
专门用来简化React应用中使用redux

5.2. react-redux将所有组件分成两大类

  1. UI组件
  1. 只负责 UI 的呈现,不带有任何业务逻辑
  2. 通过props接收数据(一般数据和函数)
  3. 不使用任何 Redux 的 API
  4. 一般保存在components文件夹下
  1. 容器组件
  1. 负责管理数据和业务逻辑,不负责UI的呈现
  2. 使用 Redux 的 API
  3. 一般保存在containers文件夹下

[react] redux react-redux_react.js_42



【补充】函数柯里化

[react] redux react-redux_UI_43

[react] redux react-redux_UI_44

5.3 基本使用

5.3.0 连接容器组件和UI组件

[react] redux react-redux_react.js_45

[react] redux react-redux_react.js_46

[react] redux react-redux_App_47

[react] redux react-redux_react.js_48


[react] redux react-redux_App_49

5.3.1 使用 分析:

下面是分析过程,理解用的,可以不看,可以直接跳到最后的写法

[react] redux react-redux_UI_50

[react] redux react-redux_javascript_51


[react] redux react-redux_react.js_52

[react] redux react-redux_App_53

[react] redux react-redux_UI_54


[react] redux react-redux_UI_55

[react] redux react-redux_UI_56


[react] redux react-redux_react.js_57


[react] redux react-redux_App_58

[react] redux react-redux_javascript_59

[react] redux react-redux_react.js_60

[react] redux react-redux_UI_61

5.3.2 整理版

index.js

[react] redux react-redux_前端_62

App.jsx

[react] redux react-redux_react.js_63

constant.js

[react] redux react-redux_前端_64

count_action.js

[react] redux react-redux_react.js_65

count_reducer.js

[react] redux react-redux_UI_66

store.js

[react] redux react-redux_App_67

contariners/Count/index.jsx

[react] redux react-redux_UI_68

components/Count/index.js

[react] redux react-redux_react.js_69

整体

[react] redux react-redux_javascript_70

总结:

(1).明确两个概念:

  • 1).UI组件:不能使用任何redux的api,只负责页面的呈现、交互等。
  • 2).容器组件:负责和redux通信,将结果交给UI组件。

(2).如何创建一个容器组件————靠react-redux 的 connect函数
​​​connect(mapStateToProps,mapDispatchToProps)(UI组件)​

  • -mapStateToProps:映射状态,返回值是一个对象
  • -mapDispatchToProps:映射操作状态的方法,返回值是一个对象

(3).备注1:容器组件中的store是靠props传进去的,而不是在容器组件中直接引入
(4).备注2:mapDispatchToProps,也可以是一个对象

5.4 优化

优化1 简写mapDispatchToProps

src\containers\Count\index.jsx

下面是分析过程:

原本写法

[react] redux react-redux_前端_71

简写

[react] redux react-redux_javascript_72

简写

[react] redux react-redux_react.js_73

最终简写

[react] redux react-redux_前端_74

优化2 Provider

容器组件可以检测redux中的状态改变,并渲染页面,所以不需要在index.js中检测了

不要在App.jsx中给子组件传递store了

index.js

容器组件可以检测redux中的状态改变,并渲染页面,所以不需要在index.js中检测了

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import store from './redux/store'
import {Provider} from 'react-redux'

ReactDOM.render(
<Provider store={store}>
<App/>
</Provider>,
document.getElementById('root')
)

App.js

不要在App.jsx中给子组件传递store了

import React, { Component } from 'react'
import Count from './containers/Count'

export default class App extends Component {
render() {
return (
<div>
<Count/>
</div>
)
}
}

下面是分析过程:

[react] redux react-redux_javascript_75

简写成:

[react] redux react-redux_UI_76

加上Provider

[react] redux react-redux_App_77

[react] redux react-redux_前端_78

优化3 整合UI组件和容器组件

每个组件两个文件夹太麻烦了,直接整合在一起就好了~

[react] redux react-redux_App_79

containers/Count/index.jsx

[react] redux react-redux_UI_80

总结:

  1. 容器组件和UI组件整合一个文件
  2. 无需自己给容器组件传递store,给​​<App/>​​​包裹一个​​<Provider store={store}>​​即可。
  3. 使用了react-redux后也不用再自己检测redux中状态的改变了,容器组件可以自动完成这个工作
  4. ​mapDispatchToProps​​也可以简单的写成一个对象
  5. 一个组件要和redux“打交道”要经过哪几步?
  1. 定义好UI组件—不暴露
  2. 引入connect生成一个容器组件,并暴露,写法如下:​​connect(​​​​state => ({key:value}), //映射状态​​​​{key:xxxxxAction} //映射操作状态的方法​​​​)(UI组件)​
  3. 在UI组件中通过​​this.props.xxxxxxx​​读取和操作状态

优化版完整代码

[react] redux react-redux_javascript_81

src/index.js

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import store from './redux/store'
import {Provider} from 'react-redux'

ReactDOM.render(
<Provider store={store}>
<App/>
</Provider>,
document.getElementById('root')
)

App.jsx

import React, { Component } from 'react'
import Count from './containers/Count'

export default class App extends Component {
render() {
return (
<div>
<Count/>
</div>
)
}
}

src\redux\constant.js

/* 
该模块是用于定义action对象中type类型的常量值,目的只有一个:便于管理的同时防止程序员单词写错
*/
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'

src\redux\count_action.js

/* 
该文件专门为Count组件生成action对象
*/
import {INCREMENT,DECREMENT} from './constant'

//同步action,就是指action的值为Object类型的一般对象
export const createIncrementAction = data => ({type:INCREMENT,data})
export const createDecrementAction = data => ({type:DECREMENT,data})

//异步action,就是指action的值为函数,异步action中一般都会调用同步action,异步action不是必须要用的。
export const createIncrementAsyncAction = (data,time) => {
return (dispatch)=>{
setTimeout(()=>{
dispatch(createIncrementAction(data))
},time)
}
}

src\redux\count_reducer.js

/* 
1.该文件是用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数
2.reducer函数会接到两个参数,分别为:之前的状态(preState),动作对象(action)
*/
import {INCREMENT,DECREMENT} from './constant'

const initState = 0 //初始化状态
export default function countReducer(preState=initState,action){
// console.log(preState);
//从action对象中获取:type、data
const {type,data} = action
//根据type决定如何加工数据
switch (type) {
case INCREMENT: //如果是加
return preState + data
case DECREMENT: //若果是减
return preState - data
default:
return preState
}
}

src\redux\store.js

/* 
该文件专门用于暴露一个store对象,整个应用只有一个store对象
*/

//引入createStore,专门用于创建redux中最为核心的store对象
import {createStore,applyMiddleware} from 'redux'
//引入为Count组件服务的reducer
import countReducer from './count_reducer'
//引入redux-thunk,用于支持异步action
import thunk from 'redux-thunk'

//暴露store
export default createStore(countReducer,applyMiddleware(thunk))

src\containers\Count\index.jsx

import React, { Component } from 'react'

//引入action
import {
createIncrementAction,
createDecrementAction,
createIncrementAsyncAction
} from '../../redux/count_action'

//引入connect用于连接UI组件与redux
import {connect} from 'react-redux'

//定义UI组件
class Count extends Component {

state = {carName:'奔驰c63'}

//加法
increment = ()=>{
const {value} = this.selectNumber
this.props.jia(value*1)
}
//减法
decrement = ()=>{
const {value} = this.selectNumber
this.props.jian(value*1)
}
//奇数再加
incrementIfOdd = ()=>{
const {value} = this.selectNumber
if(this.props.count % 2 !== 0){
this.props.jia(value*1)
}
}
//异步加
incrementAsync = ()=>{
const {value} = this.selectNumber
this.props.jiaAsync(value*1,500)
}

render() {
//console.log('UI组件接收到的props是',this.props);
return (
<div>
<h1>当前求和为:{this.props.count}</h1>
<select ref={c => this.selectNumber = c}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select> 
<button onClick={this.increment}>+</button> 
<button onClick={this.decrement}>-</button> 
<button onClick={this.incrementIfOdd}>当前求和为奇数再加</button> 
<button onClick={this.incrementAsync}>异步加</button> 
</div>
)
}
}

//使用connect()()创建并暴露一个Count的容器组件
export default connect(
state => ({count:state}),

//mapDispatchToProps的简写
{
jia:createIncrementAction,
jian:createDecrementAction,
jiaAsync:createIncrementAsyncAction,
}
)(Count)

5.5 数据共享版

效果:

[react] redux react-redux_react.js_82

code图示:

[react] redux react-redux_react.js_83

[react] redux react-redux_前端_84

[react] redux react-redux_App_85

[react] redux react-redux_前端_86

[react] redux react-redux_前端_87

[react] redux react-redux_App_88

[react] redux react-redux_javascript_89

[react] redux react-redux_UI_90

[react] redux react-redux_react.js_91

[react] redux react-redux_javascript_92

[react] redux react-redux_react.js_93

[react] redux react-redux_App_94

[react] redux react-redux_App_95

总结:

(1).定义一个Pserson组件,和Count组件通过redux共享数据。

(2).为Person组件编写:reducer、action,配置constant常量。

(3).重点:Person的reducer和Count的Reducer要使用combineReducers进行合并,

合并后的总状态是一个对象!!!

(4).交给store的是总reducer,最后注意在组件中取出状态的时候,记得“取到位”。

6. 使用上redux调试工具

6.1 安装chrome浏览器插件

Redux Dev Tools

6.2 下载工具依赖包

npm install redux-devtools-extension

在store中进行配置

import {composeWithDevTools} from 'redux-devtools-extension'

const store = createStore(allReducer,composeWithDevTools(applyMiddleware(thunk)))

[react] redux react-redux_javascript_96

7. 纯函数和高阶函数

reducer要求是一个纯函数,所以操作数组的时候,不能用push之类的方法

7.1 纯函数

  1. 一类特别的函数: 只要是同样的输入(实参),必定得到同样的输出(返回)
  2. 必须遵守以下一些约束
  1. 不得改写参数数据
  2. 不会产生任何副作用,例如网络请求,输入和输出设备
  3. 不能调用Date.now()或者Math.random()等不纯的方法
  1. redux的reducer函数必须是一个纯函数

7.2 高阶函数

  1. 理解: 一类特别的函数
  1. 情况1: 参数是函数
  2. 情况2: 返回是函数
  1. 常见的高阶函数:
  1. 定时器设置函数
  2. 数组的​​forEach()/map()/filter()/reduce()/find()/bind()​
  3. ​promise​
  4. ​react-redux​​​中的​​connect​​函数
  1. 作用: 能实现更加动态, 更加可扩展的功能

8. 最终版 简写版

所有变量名字要规范,尽量触发对象的简写形式。
reducers文件夹中,编写index.js专门用于汇总并暴露所有的reducer

[react] redux react-redux_react.js_97

code图示版

[react] redux react-redux_react.js_98

[react] redux react-redux_前端_99

[react] redux react-redux_javascript_100

[react] redux react-redux_javascript_101

[react] redux react-redux_javascript_102

[react] redux react-redux_javascript_103

[react] redux react-redux_react.js_104

[react] redux react-redux_App_105

[react] redux react-redux_App_106

[react] redux react-redux_UI_107

[react] redux react-redux_UI_108

[react] redux react-redux_javascript_109

code代码版

index.jsx

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import store from './redux/store'
import {Provider} from 'react-redux'

ReactDOM.render(
/* 此处需要用Provider包裹App,
目的是让App所有的后代容器组件都能接收到store */
<Provider store={store}>
<App/>
</Provider>,
document.getElementById('root')
)

App.js

import React, { Component } from 'react'
import Count from './containers/Count' //引入的Count的容器组件
import Person from './containers/Person' //引入的Person的容器组件

export default class App extends Component {
render() {
return (
<div>
<Count/>
<hr/>
<Person/>
</div>
)
}
}

containers/Count/index.jsx

import React, { Component } from 'react'
//引入action
import { increment, decrement, incrementAsync } from '../../redux/actions/count'

//引入connect用于连接UI组件与redux
import { connect } from 'react-redux'


//定义UI组件
class Count extends Component {

state = { carName: '奔驰c63' }

//加法
increment = () => {
const { value } = this.selectNumber
this.props.increment(value * 1)
}
//减法
decrement = () => {
const { value } = this.selectNumber
this.props.decrement(value * 1)
}
//奇数再加
incrementIfOdd = () => {
const { value } = this.selectNumber
if (this.props.count % 2 !== 0) {
this.props.increment(value * 1)
}
}
//异步加
incrementAsync = () => {
const { value } = this.selectNumber
this.props.incrementAsync(value * 1, 500)
}

render() {
//console.log('UI组件接收到的props是',this.props);
return (
<div>
<h2>我是Count组件,下方组件总人数为:{this.props.personCount}</h2>
<h4>当前求和为:{this.props.count}</h4>
<select ref={c => this.selectNumber = c}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select> 
<button onClick={this.increment}>+</button> 
<button onClick={this.decrement}>-</button> 
<button onClick={this.incrementIfOdd}>当前求和为奇数再加</button> 
<button onClick={this.incrementAsync}>异步加</button> 
</div>
)
}
}


//使用connect()()创建并暴露一个Count的容器组件
export default connect(
state => ({
count: state.count,
personCount: state.persons.length
}),
{
increment,
decrement,
incrementAsync
}
)(Count)

containers/Person/index.jsx

import React, { Component } from 'react'
import { nanoid } from 'nanoid'
import { connect } from 'react-redux'
import { addPerson } from '../../redux/actions/person'

class Person extends Component {

addPerson = () => {
const name = this.nameNode.value
const age = this.ageNode.value * 1
const personObj = { id: nanoid(), name, age }
this.props.addPerson(personObj)
this.nameNode.value = ''
this.ageNode.value = ''
}

render() {
return (
<div>
<h2>我是Person组件,上方组件求和为{this.props.count}</h2>
<input ref={c => this.nameNode = c} type="text" placeholder="输入名字" />
<input ref={c => this.ageNode = c} type="text" placeholder="输入年龄" />
<button onClick={this.addPerson}>添加</button>
<ul>
{
this.props.persons.map((p) => {
return <li key={p.id}>{p.name}--{p.age}</li>
})
}
</ul>
</div>
)
}
}

export default connect(
state => ({
persons: state.persons,
count: state.count
}),//映射状态
{
addPerson
}//映射操作状态的方法
)(Person)

src/redux/constant.js

/* 
该模块是用于定义action对象中type类型的常量值,目的只有一个:便于管理的同时防止程序员单词写错
*/
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'
export const ADD_PERSON = 'add_person'

redux/actions/count.js

/* 
该文件专门为Count组件生成action对象
*/
import { INCREMENT, DECREMENT } from "../constant";

//同步action,就是指action的值为Object类型的一般对象
export const increment = (data) => ({ type: INCREMENT, data });
export const decrement = (data) => ({ type: DECREMENT, data });

//异步action,就是指action的值为函数,异步action中一般都会调用同步action,异步action不是必须要用的。
export const incrementAsync = (data, time) => {
return (dispatch) => {
setTimeout(() => {
dispatch(increment(data));
}, time);
};
};

redux/action/person.js

import { ADD_PERSON} from '../constant'

//创建增加一个人的action动作对象
export const addPerson = personObj => ({
type: ADD_PERSON,
data: personObj
})

redux/reducers/index.js

/* 
该文件用于汇总所有的reducer为一个总的reducer
*/
//引入combineReducers,用于汇总多个reducer
import {combineReducers} from 'redux'

//引入为Count组件服务的reducer
import count from './count'

//引入为Person组件服务的reducer
import persons from './person'

//汇总所有的reducer变为一个总的reducer
export default combineReducers({
count,
persons
})

redux/reducers/count.js

/* 
1.该文件是用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数
2.reducer函数会接到两个参数,分别为:之前的状态(preState),动作对象(action)
*/
import {INCREMENT,DECREMENT} from '../constant'

const initState = 0 //初始化状态

export default function countReducer(preState=initState,action){
//从action对象中获取:type、data
const {type,data} = action

//根据type决定如何加工数据
switch (type) {
case INCREMENT: //如果是加
return preState + data
case DECREMENT: //若果是减
return preState - data
default:
return preState
}
}

redux/reducers/person.js

import {ADD_PERSON} from '../constant'

//初始化人的列表
const initState = [{id:'001',name:'tom',age:18}]

export default function personReducer(preState=initState,action){
const {type,data} = action
switch (type) {
case ADD_PERSON: //若是添加一个人
//此处不能这样写,这样会导致preState被改写了,personReducer就不是纯函数了。
//preState.unshift(data)
return [data,...preState]
default:
return preState
}
}

src/redux/store.js

/* 
该文件专门用于暴露一个store对象,整个应用只有一个store对象
*/

//引入createStore,专门用于创建redux中最为核心的store对象
import {createStore,applyMiddleware} from 'redux'

//引入汇总之后的reducer
import reducer from './reducers'

//引入redux-thunk,用于支持异步action
import thunk from 'redux-thunk'

//引入redux-devtools-extension
import {composeWithDevTools} from 'redux-devtools-extension'

//暴露store
export default createStore(reducer,composeWithDevTools(applyMiddleware(thunk)))

效果

[react] redux react-redux_UI_110

9. 项目运行打包

npm run build

全局安装serve

npm i serve -g

运行

serve -s build

或者:

serve build


参考:

​​【React】redux - 三大核心概念 - action - reducer - store - 异步编程 - react-redux - 调试工具 - 纯函数 - 高阶函数​​

​​[react] ref 的常用方法 获取input的值​​