目录:
- redux简介
- redux工作流程
- 求和案例_纯react版
- 求和案例_redux精简版
- redux完整版
- 异步action版
- 对react-redux的理解
- 连接容器组件与UI组件,react-redux基本使用
- 优化1_简写mapDispatch
- 优化2_Provider组件的使用
- 优化3_整合UI组件与容器组件
- 数据共享_编写Person组件,编写Person组件的reducer,完成数据共享
- 纯函数
- 高阶函数:
- redux开发者工具
- 最终版
- 项目打包运行
- 项目地址
1.redux简介
redux是什么?
- redux是一个专门用于做状态管理的JS库(不是react插件库)。
- 它可以用在react, angular, vue等项目中, 但基本与react配合使用。
- 作用: 集中式管理react应用中多个组件共享的状态。
什么情况下需要使用redux?
- 某个组件的状态,需要让其他组件可以随时拿到(共享)。
- 一个组件需要改变另一个组件的状态(通信)。
- 总体原则:能不用就不用, 如果不用比较吃力才考虑使用。
2.redux工作流程
redux工作流程:
redux的三个核心概念
action
- 动作的对象
- 包含2个属性
- type:标识属性, 值为字符串, 唯一, 必要属性
- data:数据属性, 值类型任意, 可选属性
- 例子:{ type: 'ADD_STUDENT',data:{name: 'tom',age:18} }
reducer
- 用于初始化状态、加工状态。
- 加工时,根据旧的state和action, 产生新的state的纯函数。
store
- 将state、action、reducer联系在一起的对象
- 如何得到此对象?
- import {createStore} from 'redux'
- import reducer from './reducers'
- const store = createStore(reducer)
- 此对象的功能?
- getState(): 得到state
- dispatch(action): 分发action, 触发reducer调用, 产生新的state
- subscribe(listener): 注册监听, 当产生了新的state时, 自动调用
3.求和案例_纯react版
Count.jsx
import React, {Component} from 'react';
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
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>
);
}
}
export default Count;
4.求和案例_redux精简版
- 去除Count组件自身的状态
- src下建立:
- -src
- -redux
- -store.js
- -count_reducer.js
- -redux
- -src
- store.js:
- 引入redux中的createStore函数,创建一个store
- createstore调用时要传入一个为其服务的reducer
- 记得暴露store对象
- count_reducer.js:
- reducer的本质是一个函数,接收: preState,action,返回加工后的状态
- reducer有两个作用:初始化状态,加工状态
- reducer被第一次调用时,是store自动触发的,传递的preState是undefined
- 在index.js中检测store中状态的改变,一旦发生改变重新渲染<App/>
- 备注: redux只负责管理状态,至于状态的改变驱动着页面的展示,要靠我们自己写。
Count.jsx
import React, {Component} from 'react';
import store from '../../redux/store'
class Count extends Component {
state = {carName: '奔驰c63'}
// componentDidMount() {
// 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
setTimeout(() => {
store.dispatch({type: 'increment', data: value * 1})
}, 500)
}
render() {
return (
<div>
<h1>车名字:{this.state.carName}</h1>
<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>
);
}
}
export default Count;
store.js
import {createStore} from 'redux'
import countReducer from './count_reducer'
export default createStore(countReducer)
count_reducer.js
const initState = 0
export default function countReducer(preState = initState, action) {
const {type, data} = action
switch (type) {
case 'increment':
return preState + data
case 'decrement':
return preState - data
default:
return preState
}
}
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import store from "./redux/store";
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App/>);
store.subscribe(() => {
root.render(<App/>);
})
5.redux完整版
新增文件:
- count_action.js 专门用于创建action对象
- constant.js放置容易写错的type值
Count.jsx
import React, {Component} from 'react';
import store from '../../redux/store'
import {createIncrementAction, createDecrementAction} from '../../redux/count_action'
class Count extends Component {
state = {carName: '奔驰c63'}
// componentDidMount() {
// 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
setTimeout(() => {
store.dispatch(createIncrementAction(value * 1))
}, 500)
}
render() {
return (
<div>
<h1>车名字:{this.state.carName}</h1>
<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>
);
}
}
export default Count;
constant.js
export const INCREMENT = 'incrment'
export const DECREMENT = 'decrement'
count_action.js
import {DECREMENT, INCREMENT} from "./constant";
export const createIncrementAction = data => ({type: INCREMENT, data})
export const createDecrementAction = data => ({type: DECREMENT, data})
count_reducer.js
import {INCREMENT, DECREMENT} from "./constant";
const initState = 0
export default function countReducer(preState = initState, action) {
const {type, data} = action
switch (type) {
case INCREMENT:
return preState + data
case DECREMENT:
return preState - data
default:
return preState
}
}
store.js
import {createStore} from 'redux'
import countReducer from './count_reducer'
export default createStore(countReducer)
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import store from "./redux/store";
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App/>);
store.subscribe(() => {
root.render(<App/>);
})
6.异步action版
- 明确:延迟的动作不想交给组件自身,想交给action
- 何时需要异步action:想要对状态进行操作,但是具体的数据靠异步任务返回。
- 具体编码:
- yarn add redux-thunk,并配置在store中
- 创建action的函数不再返回一般对象,而是一个函数,该函数中写异步任务。
- 异步任务有结果后,分发一个同步的action去真正操作数据。
- 备注:异步action不是必须要写的,完全可以自己等待异步任务的结果了再去分发同步action
Count.jsx
import React, {Component} from 'react';
import store from '../../redux/store'
import {createIncrementAction, createDecrementAction, createIncrementAsyncAction} from '../../redux/count_action'
class Count extends Component {
state = {carName: '奔驰c63'}
// componentDidMount() {
// 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
// setTimeout(() => {
// store.dispatch(createIncrementAction(value * 1))
store.dispatch(createIncrementAsyncAction(value * 1, 500))
// }, 500)
}
render() {
return (
<div>
<h1>车名字:{this.state.carName}</h1>
<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>
);
}
}
export default Count;
count_action.js
import {DECREMENT, INCREMENT} from "./constant";
//同步action,就是指action的值为object类型的一般对象
export const createIncrementAction = data => ({type: INCREMENT, data})
export const createDecrementAction = data => ({type: DECREMENT, data})
//异步action,就是指action的值为函数
export const createIncrementAsyncAction = (data, time) => {
return (dispatch) => {
setTimeout(() => {
dispatch(createIncrementAction(data))
}, time)
}
}
store.js
import {createStore, applyMiddleware} from 'redux'
import countReducer from './count_reducer'
import thunk from 'redux-thunk'
export default createStore(countReducer, applyMiddleware(thunk))
7.对react-redux的理解
8.连接容器组件与UI组件,react-redux基本使用
- 明确两个概念:
- UI组件:不能使用任何redux的api,只负责页面的呈现、交互等。
- 容器组件:负责和redux通信,将结果交给UT组件。
- 如何创建一个容器组件-----靠react-redux 的connect函数
- connect(mapStateToProps,mapDispatchToProps)(UI组件)
- mapstateToProps:映射状态,返回值是一个对象
- mapDispatchToProps:映射操作状态的方法,返回值是一个对象
- 备注:容器组件中的store是靠props传进去的,而不是在容器组件中直接引入
components/Count/Count.jsx
import React, {Component} from 'react';
class Count extends Component {
state = {carName: '奔驰c63'}
increment = () => {
const {value} = this.selectNumber
this.props.add(value * 1)
}
decrement = () => {
const {value} = this.selectNumber
this.props.sub(value * 1)
}
incrementIfOdd = () => {
const {value} = this.selectNumber
if (this.props.count % 2 !== 0) {
this.props.add(value * 1)
}
}
incrementAsync = () => {
const {value} = this.selectNumber
this.props.addAsync(value * 1, 500)
}
render() {
return (
<div>
<h1>车名字:{this.state.carName}</h1>
<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>
);
}
}
export default Count;
containers/Count/Count.jsx
import CountUI from '../../components/Count/Count'
import {connect} from 'react-redux'
import {createDecrementAction, createIncrementAction, createIncrementAsyncAction} from "../../redux/count_action";
import {number} from "prop-types";
function mapStateToProps(state) {
return {count: state}
}
function mapDispatchToProps(dispatch) {
return {
add: (number) => {
dispatch(createIncrementAction(number))
},
sub: (number) => {
dispatch(createDecrementAction(number))
},
addAsync: (number, time) => {
dispatch(createIncrementAsyncAction(number, time))
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(CountUI)
constant.js
export const INCREMENT = 'incrment'
export const DECREMENT = 'decrement'
count_action.js
import {DECREMENT, INCREMENT} from "./constant";
//同步action,就是指action的值为object类型的一般对象
export const createIncrementAction = data => ({type: INCREMENT, data})
export const createDecrementAction = data => ({type: DECREMENT, data})
//异步action,就是指action的值为函数
export const createIncrementAsyncAction = (data, time) => {
return (dispatch) => {
setTimeout(() => {
dispatch(createIncrementAction(data))
}, time)
}
}
count_reducer.js
import {INCREMENT, DECREMENT} from "./constant";
const initState = 0
export default function countReducer(preState = initState, action) {
const {type, data} = action
switch (type) {
case INCREMENT:
return preState + data
case DECREMENT:
return preState - data
default:
return preState
}
}
store.js
import {createStore, applyMiddleware} from 'redux'
import countReducer from './count_reducer'
import thunk from 'redux-thunk'
export default createStore(countReducer, applyMiddleware(thunk))
App.js
import React, {Component} from 'react';
import Count from "./containers/Count/Count";
import store from "./redux/store";
class App extends Component {
render() {
return (
<div>
<Count store={store}></Count>
</div>
);
}
}
export default App;
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import store from "./redux/store";
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App/>);
store.subscribe(() => {
root.render(<App/>);
})
9.优化1_简写mapDispatch
containers/Count/Count.jsx
import CountUI from '../../components/Count/Count'
import {connect} from 'react-redux'
import {createDecrementAction, createIncrementAction, createIncrementAsyncAction} from "../../redux/count_action";
export default connect(
state => ({count: state}),
// (dispatch) => (
// {
// add: number => dispatch(createIncrementAction(number)),
// sub: number => dispatch(createDecrementAction(number)),
// addAsync: (number, time) => dispatch(createIncrementAsyncAction(number, time))
//
// })
{
add: createIncrementAction,
sub: createDecrementAction,
addAsync: createIncrementAsyncAction
}
)(CountUI)
10.优化2_Provider组件的使用
App.js
import React, {Component} from 'react';
import Count from "./containers/Count/Count";
class App extends Component {
render() {
return (
<div>
<Count></Count>
</div>
);
}
}
export default App;
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import {Provider} from "react-redux";
import store from "./redux/store";
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
<App/>
</Provider>
);
11.优化3_整合UI组件与容器组件
- 容器组件和UI组件组合成一个文件
- 无需自己给容器组件传递store,给<App/>包裹一个<Provider store={store}>即可。
- 使用了react-redux后也不用再自己检测redux中状态的改变了,容器组件可以自动完成这个工作。
- mapDispatchToProps也可以简单的写成一个对象
- 一个组件要和redux“打交道”要经过哪几步?
- 定义好UI组件---不暴露
- 引入connect生成一个容器组件,并暴露,写法如下:
- connect(
- state =>({key:value})
- {key : xxxxxAction}
- )(UI组件)
- 在UI组件中通过this.props.xxxxxxx读取和操作状态
containers/Count/Count.jsx
import React, {Component} from 'react';
import {connect} from 'react-redux'
import {createDecrementAction, createIncrementAction, createIncrementAsyncAction} from "../../redux/count_action";
class Count extends Component {
state = {carName: '奔驰c63'}
increment = () => {
const {value} = this.selectNumber
this.props.add(value * 1)
}
decrement = () => {
const {value} = this.selectNumber
this.props.sub(value * 1)
}
incrementIfOdd = () => {
const {value} = this.selectNumber
if (this.props.count % 2 !== 0) {
this.props.add(value * 1)
}
}
incrementAsync = () => {
const {value} = this.selectNumber
this.props.addAsync(value * 1, 500)
}
render() {
console.log(this.props)
return (
<div>
<h1>车名字:{this.state.carName}</h1>
<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>
);
}
}
export default connect(
state => ({count: state}),
{
add: createIncrementAction,
sub: createDecrementAction,
addAsync: createIncrementAsyncAction
}
)(Count)
12.数据共享_编写Person组件,编写Person组件的reducer,完成数据共享
- 定义一个Pserson组件,和Count组件通过redux共享数据
- 为Person组件编写: reducer、action,配置constant常量。
- 重点: Person的reducer和Count的Reducer要使用combineReducers进行合并,合并后的总状态是一个对象!! !
- 交给store的是总reducer,最后注意在组件中取出状态的时候,记得“取到位”。
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import {Provider} from "react-redux";
import store from "./redux/store";
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
<App/>
</Provider>
);
App.js
import React, {Component} from 'react';
import Count from "./containers/Count/Count";
import Person from "./containers/Person/Person";
class App extends Component {
render() {
return (
<div>
<Count></Count>
<hr></hr>
<Person></Person>
</div>
);
}
}
export default App;
store.js
import {createStore, applyMiddleware, combineReducers} from 'redux'
import countReducer from './reducers/count'
import thunk from 'redux-thunk'
import personReducer from "./reducers/person";
const allReducer = combineReducers({
he: countReducer,
rens: personReducer
})
export default createStore(allReducer, applyMiddleware(thunk))
constant.js
export const INCREMENT = 'incrment'
export const DECREMENT = 'decrement'
export const ADD_PERSON = 'add_person'
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:
return [data, ...preState]
default:
return preState;
}
}
reducers/count.js
import {INCREMENT, DECREMENT} from "../constant";
const initState = 0
export default function countReducer(preState = initState, action) {
const {type, data} = action
switch (type) {
case INCREMENT:
return preState + data
case DECREMENT:
return preState - data
default:
return preState
}
}
actions/person.js
import {ADD_PERSON} from '../constant'
export const createAddPersonAction = personObj => ({type: ADD_PERSON, data: personObj})
actions/count.js
import {DECREMENT, INCREMENT} from "../constant";
//同步action,就是指action的值为object类型的一般对象
export const createIncrementAction = data => ({type: INCREMENT, data})
export const createDecrementAction = data => ({type: DECREMENT, data})
//异步action,就是指action的值为函数
export const createIncrementAsyncAction = (data, time) => {
return (dispatch) => {
setTimeout(() => {
dispatch(createIncrementAction(data))
}, time)
}
}
Person.jsx
import React, {Component} from 'react';
import {nanoid} from "nanoid";
import {connect} from "react-redux";
import {createAddPersonAction} 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.jiaYiRen(personObj)
this.nameNode.value = ''
this.ageNode.value = ''
}
render() {
return (
<div>
<h2>我是person组件,上方组件求和为{this.props.he}</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.yiduiren.map((p) => {
return <li key={p.id}>{p.name}--{p.age}</li>
})
}
</ul>
</div>
);
}
}
export default connect(
state => ({yiduiren: state.rens, he: state.he}),
{jiaYiRen: createAddPersonAction}
)(Person)
count.jsx
import React, {Component} from 'react';
import {connect} from 'react-redux'
import {createDecrementAction, createIncrementAction, createIncrementAsyncAction} from "../../redux/actions/count";
class Count extends Component {
increment = () => {
const {value} = this.selectNumber
this.props.add(value * 1)
}
decrement = () => {
const {value} = this.selectNumber
this.props.sub(value * 1)
}
incrementIfOdd = () => {
const {value} = this.selectNumber
if (this.props.count % 2 !== 0) {
this.props.add(value * 1)
}
}
incrementAsync = () => {
const {value} = this.selectNumber
this.props.addAsync(value * 1, 500)
}
render() {
return (
<div>
<h2>我是Count组件,下方组件总人数为:{this.props.renshu}</h2>
<h2>当前求和为:{this.props.count}</h2>
<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>
);
}
}
export default connect(
state => ({count: state.he, renshu: state.rens.length}),
{
add: createIncrementAction,
sub: createDecrementAction,
addAsync: createIncrementAsyncAction
}
)(Count)
项目结构:
运行结果:
13.纯函数
- 一类特别的函数:只要是同样的输入(实参),必定得到同样的输出(返回)
- 必须遵守以下一些约束
- 不得改写参数数据
- 不会产生任何副作用,例如网络请求,输入和输出设备
- 不能调用Date.now)或者Math.random()等不纯的方法
- redux的reducer函数必须是一个纯函数
14.高阶函数:
- 理解:一类特别的函数
- 情况1:参数是函数2
- 情况2:返回是函数
- 常见的高阶函数:
- 定时器设置函数
- 数组的forEach()/map(/filter(/reduce()/find0/bind()
- promise
15.redux开发者工具
- yarn add redux-devtools-extension
- store中进行配置
- import {composewithDevTools} from 'redux-devtools-extension'
- const store = createStore(allReducer,composelithDevTools(applyMiddleware(thunk)))
16. 最终版
- 所有变量名字要规范,尽量触发对象的简写形式。
- reducers文件夹中,编写index.js专门用于汇总并暴露所有的reducer
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import {Provider} from "react-redux";
import store from "./redux/store";
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
<App/>
</Provider>
);
App.js
import React, {Component} from 'react';
import Count from "./containers/Count/Count";
import Person from "./containers/Person/Person";
class App extends Component {
render() {
return (
<div>
<Count></Count>
<hr></hr>
<Person></Person>
</div>
);
}
}
export default App;
store.js
import {createStore, applyMiddleware, combineReducers} from 'redux'
import thunk from 'redux-thunk'
import {composeWithDevTools} from "redux-devtools-extension";
import allReducer from "./reducers";
export default createStore(allReducer, composeWithDevTools(applyMiddleware(thunk)))
constant.js
export const INCREMENT = 'incrment'
export const DECREMENT = 'decrement'
export const ADD_PERSON = 'add_person'
reducers/count.js
import {INCREMENT, DECREMENT} from "../constant";
const initState = 0
export default function countReducer(preState = initState, action) {
const {type, data} = action
switch (type) {
case INCREMENT:
return preState + data
case DECREMENT:
return preState - data
default:
return preState
}
}
reducers/index.js
import {combineReducers} from "redux";
import countReducer from "./count";
import personReducer from "./person";
const allReducer = combineReducers({
count: countReducer,
persons: personReducer
})
export default allReducer
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:
return [data, ...preState]
default:
return preState;
}
}
actions/count.js
import {DECREMENT, INCREMENT} from "../constant";
//同步action,就是指action的值为object类型的一般对象
export const increment = data => ({type: INCREMENT, data})
export const decrement = data => ({type: DECREMENT, data})
//异步action,就是指action的值为函数
export const incrementAsync = (data, time) => {
return (dispatch) => {
setTimeout(() => {
dispatch(increment(data))
}, time)
}
}
actions/person.js
import {ADD_PERSON} from '../constant'
export const addPerson = personObj => ({type: ADD_PERSON, data: personObj})
Person.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)
Count.jsx
import React, {Component} from 'react';
import {connect} from 'react-redux'
import {
decrement,
increment,
incrementAsync
} from "../../redux/actions/count";
class Count extends Component {
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() {
return (
<div>
<h2>我是Count组件,下方组件总人数为:{this.props.personCount}</h2>
<h2>当前求和为:{this.props.count}</h2>
<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>
);
}
}
export default connect(
state => ({count: state.count, personCount: state.persons.length}),
{
increment,
decrement,
incrementAsync
}
)(Count)
17.项目打包运行
1.下载依赖
2.build
3.启动服务器:
4.运行结果:
18.项目地址
https://gitee.com/coderPatrickStar/react/tree/master/20231003