一、redux理解
1.学习文档
(1)英文文档:https://redux.js.org/
(2)中文文档:https://www.redux.org.cn/
(3)Github:https://github.com/reactjs/redux
2.redux是什么
(1)redux是一个专门用于做状态管理的JS库(不是react插件库)
(2)它可以用在react、angular、vue等项目中,但基本与react配合使用
(3)作用:集中式管理react应用中多个组件共享的状态
3.什么情况下需要使用redux
(1)某个组件的状态,需要让其他组件可以随时拿到(共享)
(2)一个组件需要改变另一个组件的状态(通信)
(3)总体原则:能不用就不用,如果不用比较吃力才考虑使用
4.redux原理图
二、redux的三个核心概念
1.action
(1)动作的对象
(2)包含2个属性
type:标识属性,值为字符串,唯一,必要属性
data:数据属性,值类型任意,可选属性
(3)例子:{type:'ADD_STUDENT',data:{'name:'tom',age:18}}
2.reducer
(1)用于初始化状态,加工状态
(2)加工时,根据旧的state和action,产生新的state的纯函数。
3.store
(1)将state、action、reducer联系在一起的对象
(2)如何得到此对象?
import {createStore} from 'redux'
import reducer from './reducers'
const store = createStore(reducer)
(3)此对象的功能
getState(): 得到state
dispatch(action):分发action,触发reducer调用,产生新的state
subscribe(listener):注册监听,当产生了新的state时,自动调用
三、求和案例
1.纯react
import React, { Component } from 'react'
export default class Count extends Component {
state = {
count : 0
}
// 加法
increment = () => {
const {value} = this.selectNumber
const {count} = this.state
this.setState({
count:count+value*1
})
}
// 减法
decrement = () => {
const {value} = this.selectNumber
const {count} = this.state
this.setState({
count:count-value*1
})
}
// 奇数再加
incrementIfOdd = () => {
const {value} = this.selectNumber
const {count} = this.state
if (count%2 !== 0) {
this.setState({
count:count+value*1
})
}
}
// 异步加
incrementAsync = () => {
const {value} = this.selectNumber
const {count} = this.state
if (count%2 !== 0) {
setTimeout(() => {
this.setState({
count:count+value*1
})
}, 500)
}
}
render() {
return (
<div>
<h1>当前求和为:{this.state.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>
)
}
}
2.精简版
(1)去除Count自身的状态
(2).src下建立:
-src
-redux
-store.js
-count_reducer.js
(3)store.js
引入redux中的createStore函数,创建一个store
createStore调用时传入一个为其服务的reducer
记得暴露store对象
(4)count_reducer.js
reducer的本质是一个函数,接收preState,action,返回加工后的状态
reducer有两个作用:初始化状态,加工状态
reducer被第一次调用时,是store自动触发的,传递的preState是undefined
(5)在index.js中检测store中状态的改变,一旦发生改变重新渲染<App/>
备注:redux只负责管理状态,至于状态的改变驱动页面的展示,要靠自己写
// index.js
// 引入React
import React from 'react';
// 引入ReactDOM
import ReactDOM from 'react-dom/client';
// 引入App组件
import App from './App';
import store from './redux/store'
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
store.subscribe(() => {
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
})
// Components/Count/index.jsx
import React, { Component } from 'react'
// 引入store用于获取store中的状态
import store from '../../redux/store'
export default class Count extends Component {
state = {
count : 0
}
// componentDidMount() {
// // 检测redux中状态的变化,只要变化,就调用render
// store.subscribe(() => {
// this.setState({})
// })
// }
// 加法
increment = () => {
const {value} = this.selectNumber
store.dispatch({type: 'increment', data: value*1})
}
// 减法
decrement = () => {
const {value} = this.selectNumber
store.dispatch({type: 'decrement', data: value*1})
}
// 奇数再加
incrementIfOdd = () => {
const {value} = this.selectNumber
const count = store.getState()
if (count%2 !== 0) {
store.dispatch({type: 'increment', data: value*1})
}
}
// 异步加
incrementAsync = () => {
const {value} = this.selectNumber
const count = store.getState()
if (count%2 !== 0) {
setTimeout(() => {
store.dispatch({type: 'increment', data: value*1})
}, 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>
)
}
}
// redux/count_reducer.js
/*
1.该文件是用于创建一个为Count组件服务的reducer,reducer的本质是一个函数
2.reducer函数会接收到两个函数,分别为:之前的状态preState,动作对象action
*/
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/store.js
/* 该文件专门用于暴露一个store对象,整个应用只有一个store对象 */
// 引入createStore,专门用于创建redux中最为核心的store对象
// 5.0.1,createStore弃用了该版本
import { legacy_createStore as createStore} from 'redux'
// import { createStore } from "redux"
// 引入为Count组件服务的reducer
import countReducer from './count_reducer'
// 暴露store
export default createStore(countReducer)
3.完整版
(1) 新增两文件:
count_action.js: 专门用于创建action对象
constant.js: 放置由于容易写错action中的type
// Count.jsx
import React, { Component } from 'react'
// 引入store用于获取store中的状态
import store from '../../redux/store'
// 引入actionCrator,专门用于常见action对象
import {createIncrementAction,createDecrementAction} from '../../redux/count_action'
export default class Count extends Component {
state = {
count : 0
}
// componentDidMount() {
// // 检测redux中状态的变化,只要变化,就调用render
// store.subscribe(() => {
// this.setState({})
// })
// }
// 加法
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
const count = store.getState()
if (count%2 !== 0) {
setTimeout(() => {
store.dispatch(createIncrementAction(value*1))
}, 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>
)
}
}
// reducer/constant.js
/*
该模块是用于定义action对象中type类型的常量值,目的只有一个,便于管理的同时防止程序员单词写错
*/
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'
// reducer/count_action.js
/*
该文件专门为Count组件生成action对象
*/
import {INCREMENT,DECREMENT} from './constant'
export const createIncrementAction = data => ({type: INCREMENT, data})
export const createDecrementAction = data => ({type: DECREMENT, data})
// reducer/store.js
/* 该文件专门用于暴露一个store对象,整个应用只有一个store对象 */
// 引入createStore,专门用于创建redux中最为核心的store对象
// 5.0.1,createStore弃用了该版本
import { legacy_createStore as createStore} from 'redux'
// import { createStore } from "redux"
// 引入为Count组件服务的reducer
import countReducer from './count_reducer'
// 暴露store
export default createStore(countReducer)
// reducer/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){
// 从action对象中获取type,data
const {type,data} =action
// 根据type决定如何加工数据
switch (type) {
case INCREMENT: // 如果是加
return preState + data
case DECREMENT: // 如果是减
return preState - data
default:
return preState
}
}
4.异步action版
(1)明确:延迟的动作不想交给组件自身,想交给action
(2)何时需要异步action,想要对状态进行操作,但是具体的数据靠异步任务返回
(3)具体编码:
npm i redux-thunk,并配置在store中
创建action的函数不再返回一般对象,而是一个函数,该函数中写异步任务返回
异步任务有结果后,分发一个同步的action去真正操作数据
(4)备注:异步action不是必须要写的,完全可以自己等待异步任务的结果再去分发同步action
// src/Components/Count/index.jsx
import React, { Component } from 'react'
// 引入store用于获取store中的状态
import store from '../../redux/store'
// 引入actionCrator,专门用于常见action对象
import {createIncrementAction,createDecrementAction, createIncrementAsyncAction} from '../../redux/count_action'
export default class Count extends Component {
state = {
count : 0
}
// componentDidMount() {
// // 检测redux中状态的变化,只要变化,就调用render
// store.subscribe(() => {
// this.setState({})
// })
// }
// 加法
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
const count = store.getState()
if (count%2 !== 0) {
setTimeout(() => {
store.dispatch(createIncrementAsyncAction(value*1, 500))
}, 500)
}
}
render() {
return (
<div>
{/*
(1)明确:延迟的动作不想交给组件自身,想交给action
(2)何时需要异步action,想要对状态进行操作,但是具体的数据靠异步任务返回
(3)具体编码:
npm i redux-thunk,并配置在store中
创建action的函数不再返回一般对象,而是一个函数,该函数中写异步任务返回
异步任务有结果后,分发一个同步的action去真正操作数据
(4)备注:异步action不是必须要写的,完全可以自己等待异步任务的结果再去分发同步action
*/}
<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>
)
}
}
// src/redux/constant.js
/*
该模块是用于定义action对象中type类型的常量值,目的只有一个,便于管理的同时防止程序员单词写错
*/
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'
// src/redux/count_action.js
/*
该文件专门为Count组件生成action对象
*/
// 同步action,就是指action的值为函数
import {INCREMENT,DECREMENT} from './constant'
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){
// 从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对象
// 5.0.1,createStore弃用了该版本
import { legacy_createStore as createStore, applyMiddleware} from 'redux'
// import { createStore } from "redux"
// 引入为Count组件服务的reducer
import countReducer from './count_reducer'
// 引入redux-thunk,用于支持异步action
import {thunk} from 'redux-thunk'
// 暴露store
export default createStore(countReducer,applyMiddleware(thunk))
四、react-redux
1.理解
2.react-redux的基本使用
(1)明确两个概念:
UI组件:不能使用在redux的api,只负责页面的呈现,交互等
容器组件:负责和redux通信,将结果交给UI组件
(2)如何创建一个容器组件----redux的connect函数
connect(mapStateToProps,mapDispatchToProps)(UI组件)
mapStateToProps:映射状态,返回值是一个对象
mapDispatchToProps:映射操作状态的方法,返回值是一个对象
(3)备注:容器组件中的store是靠props传进去的,而不是在容器组件中直接引入
代码示例:
// src/Components/Count/index.jsx
import React, { Component } from 'react'
export default class Count extends Component {
state = {
count : 0
}
// 加法
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
if (this.props.count % 2 !== 0){
this.props.jiaAsync(value*1, 500)
}
}
render() {
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>
)
}
}
// src/containers/Count.jsx
// 引入Count的UI组件
import Count from "../../components/Count";
// 引入connect用于连接UI组件与redux
import { connect } from "react-redux";
import { createIncrementAction,createDecrementAction, createIncrementAsyncAction } from "../../redux/count_action";
// mapStateToProps函数返回的是一个对象
// 返回的对象中的key就作为传递给UI组件的props的key,value就作为传递给UI组件props的value-状态
// mapStateToProps用于传递状态
function mapStateToProps (state) {
return {count:state}
}
// mapDispatchToProps函数返回的是一个对象
// 返回的对象中的key就作为传递给UI组件的props的key,value就作为传递给UI组件props的value-操作状态的方法
// mapDispatchToProps用于传递操作状态的方法
function mapDispatchToProps (dispatch) {
return {
// 通知redux执行加法
jia:number => dispatch(createIncrementAction(number)),
jian:number => dispatch(createDecrementAction(number)),
jiaAsync: (number, time) => dispatch(createIncrementAsyncAction(number,time))
}
}
// 使用connect()()创建并暴露一个容器组件,
export default connect(mapStateToProps,mapDispatchToProps)(Count)
// src/reducx/constant.js
/*
该模块是用于定义action对象中type类型的常量值,目的只有一个,便于管理的同时防止程序员单词写错
*/
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'
// src/redux/count_action.js
/*
该文件专门为Count组件生成action对象
*/
// 同步action,就是指action的值为函数
import {INCREMENT,DECREMENT} from './constant'
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){
// 从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对象
// 5.0.1,createStore弃用了该版本
import { legacy_createStore as createStore, applyMiddleware} from 'redux'
// import { createStore } from "redux"
// 引入为Count组件服务的reducer
import countReducer from './count_reducer'
// 引入redux-thunk,用于支持异步action
import {thunk} from 'redux-thunk'
// 暴露store
export default createStore(countReducer,applyMiddleware(thunk))
// App.js
import React, { Component } from 'react'
import Count from './containers/Count'
// 引入store
import store from "./redux/store";
export default class App extends Component {
render() {
return (
<div>
<Count store={store}/>
</div>
)
}
}
// index.js
// 引入React
import React from 'react';
// 引入ReactDOM
import ReactDOM from 'react-dom/client';
// 引入App组件
import App from './App';
import store from './redux/store'
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
store.subscribe(() => {
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
})
文件目录:
3.react-redux中mapDispatchToProps优化
mapDispatchToProps也可以是一个对象
// src/Containers/Count.jsx
// 引入Count的UI组件
import Count from "../../components/Count";
// 引入connect用于连接UI组件与redux
import { connect } from "react-redux";
import { createIncrementAction,createDecrementAction, createIncrementAsyncAction } from "../../redux/count_action";
// 使用connect()()创建并暴露一个容器组件,
export default connect(
state => ({count:state}),
// mapDispatchToProps一般写法
// dispatch => ({
// jia:number => dispatch(createIncrementAction(number)),
// jian:number => dispatch(createDecrementAction(number)),
// jiaAsync: (number, time) => dispatch(createIncrementAsyncAction(number,time))
// })
// mapDispatchToProps的简写
{
jia: createIncrementAction,
jian: createDecrementAction,
jiaAsync: createIncrementAsyncAction
}
)(Count)
4.Provider的使用
// App.js
import React, { Component } from 'react'
import Count from './containers/Count'
export default class App extends Component {
render() {
return (
<div>
<Count/>
</div>
)
}
}
// index.js
// 引入React
import React from 'react';
// 引入ReactDOM
import ReactDOM from 'react-dom/client';
// 引入App组件
import App from './App';
import store from './redux/store';
import { Provider } from 'react-redux';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
5.整合UI组件和容器组件
将src/Component/Count/index.jsx中的组件中的内容移入到容器组件中,其余文件不变。
// 引入connect用于连接UI组件与redux
import { connect } from "react-redux";
import { createIncrementAction,createDecrementAction, createIncrementAsyncAction } from "../../redux/count_action";
import React, { Component } from 'react'
class Count extends Component {
state = {
count : 0
}
// 加法
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
if (this.props.count % 2 !== 0){
this.props.jiaAsync(value*1, 500)
}
}
render() {
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()()创建并暴露一个容器组件,
export default connect(
state => ({count:state}),
// mapDispatchToProps一般写法
// dispatch => ({
// jia:number => dispatch(createIncrementAction(number)),
// jian:number => dispatch(createDecrementAction(number)),
// jiaAsync: (number, time) => dispatch(createIncrementAsyncAction(number,time))
// })
// mapDispatchToProps的简写
{
jia: createIncrementAction,
jian: createDecrementAction,
jiaAsync: createIncrementAsyncAction
}
)(Count)
6.react-redux从基本使用到优化完成总结
(1)容器组件和UI组件整合一个文件
(2)无需自己给容器组件传递store,给<App/>包裹一个<Provider store={store}>即可
(3)使用了react-redux后也不用再自己检测redux中状态的改变了,容器组件可以自动完成这个工作
(4)mapDispatchToProps也可以简单的写成一个对象
(5)一个组件要和redux“打交道”要经过哪几步
定义好UI组件 --- 不暴露
引入connect生成一个容器组件,并暴露,写法如下:
connect(
state => {{key:value}}, 映射状态
{key:xxxxAction} 映射状态操作的方法
)(UI组件)
(6)在UI组件中通过this.props.xxxx读取和操作状态
五、react-redux整体使用数据共享案例
1.Person(添加人)与Count(求和)数据共享
(1)定义一个Person组件,和Count组件通过redux共享数据
(2)为Person组件编写,reducer、action,配置constant常量
(3)重点:Person的reducer和Count的reducer要使用combineReducers进行合并
合并后的总状态是一个对象
(4)交给store的是总reducer,注意在组件中取出状态的时候,记得“取到位”
// 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>
)
}
}
// index.js
// 引入React
import React from 'react';
// 引入ReactDOM
import ReactDOM from 'react-dom/client';
// 引入App组件
import App from './App';
import store from './redux/store';
import { Provider } from 'react-redux';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
{/* 此处需要用Provider包裹App,目的是让App所有的后代容器组件都能接收到store */}
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
// src/containers/Count/index.jsx
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { increment, decrement, incrementAsync } from '../../redux/actions/count'
class Count extends Component {
state = {
count : 0
}
// 加法
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
if (this.props.count % 2 !== 0){
this.props.incrementAsync(value*1, 500)
}
}
render() {
return (
<div>
<h2>我是Count组件,下方组件总人数{this.props.personNum}</h2>
<h3>当前求和为:{this.props.count}</h3>
<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()()创建并暴露一个容器组件,
export default connect(
state => ({
count:state.count,
personNum:state.persons.length}),
// mapDispatchToProps一般写法
// dispatch => ({
// jia:number => dispatch(createIncrementAction(number)),
// jian:number => dispatch(createDecrementAction(number)),
// jiaAsync: (number, time) => dispatch(createIncrementAsyncAction(number,time))
// })
// mapDispatchToProps的简写
{
increment,
decrement,
incrementAsync
}
)(Count)
// src/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
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/actions/count.js
/*
该文件专门为Count组件生成action对象
*/
// 同步action,就是指action的值为函数
import {INCREMENT,DECREMENT} from '../constant'
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)
}
}
// src/redux/actions/person.js
import { ADD_PERSON } from "../constant";
// 创建增加一个人的action动作对象
export const addPerson = (personObj) => ({type:ADD_PERSON, data:personObj})
// src/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
}
}
// src/redux/reducers/index.js
/*
该文件用于汇总所有的reducer为一个总的reducer
*/
import { combineReducers} from 'redux'
// 引入为Count组件服务的reducer
import count from './count'
// 引入为Person组件服务的reducer
import persons from './person'
// 汇总所有的reducer
export default combineReducers({
count,
persons
})
// src/redux/reducers/person.js
import { ADD_PERSON } from "../constant";
// 初始化人的状态
const initState = [
{id: '001',name: 'tom', age:10}
]
export default function personReducer(preState = initState, action) {
const {type, data} = action
switch (type) {
case ADD_PERSON: // 若添加一个人
return [data, ...preState]
default:
return preState
}
}
// src/redux/constant.js
/*
该模块是用于定义action对象中type类型的常量值,目的只有一个,便于管理的同时防止程序员单词写错
*/
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'
export const ADD_PERSON = 'add_person'
// src/redux/store.js
/* 该文件专门用于暴露一个store对象,整个应用只有一个store对象 */
// 引入createStore,专门用于创建redux中最为核心的store对象
// 5.0.1,createStore弃用了该版本
import { legacy_createStore as createStore, applyMiddleware, combineReducers} from 'redux'
// import { createStore } from "redux"
// 引入汇总之后的reducer
import reducer from './reducers'
// 引入redux-thunk,用于支持异步action
import {thunk} from 'redux-thunk'
// 暴露store
export default createStore(
reducer,
applyMiddleware(thunk))
2.纯函数
(1)一类特别的函数:只要是同样的输入(实参),必定得到同样的输出(返回)
(2)必须遵守一下一些约束
不得改写参数数据
不会产生任何副作用,例如网络请求,输入和输出设备
不能调用Date.now()或者Math.random()等不纯的方法
(3)redux的reducer函数必须是一个纯函数
六、react-redux开发者工具的使用
(1)npm i redux-devtools-extension
(2)store中进行配置
import {composeWithDevTools} from 'redux-devtools-extension'
const store = createStore(allReducer,composeWithDevTools(applyMiddleware(thunk)))