海口网站制作策划,电商培训机构排名前十,小手工在家做,vi设计作品图React#xff08;react18#xff09;中组件通信05——redux ➕ react-redux#xff08;含数据共享#xff09; 1. 前言1.1 React中组件通信的其他方式1.2 介绍React-Redux1.2.1 简单介绍React-Redux1.2.2 官网 1.3 安装react-redux 2. 简单改写redux的例子2.1 提供store2.2… Reactreact18中组件通信05——redux ➕ react-redux含数据共享 1. 前言1.1 React中组件通信的其他方式1.2 介绍React-Redux1.2.1 简单介绍React-Redux1.2.2 官网 1.3 安装react-redux 2. 简单改写redux的例子2.1 提供store2.2 连接 Components UI组件修改2.2.1 连接 Components2.2.2 修改UI组件2.2.3 看效果 2.3 连接 Components——优化优化容器组件2.4 优化容器组件可怕的精简2.5 附代码 3. 多reducer实现数据共享3.1 介绍 combineReducers()函数3.2 多reducer整合的例子3.2.1 想实现的效果3.2.2 项目目录设计结构3.2.3 将3个reducer整合或者说拆分reducer3.2.4 每个组件的三个核心文件3.2.4.1 简单介绍——以cat为例3.2.4.2 关于dog 和 petPark 的 3.3 实现数据共享3.3.1 实现数据共享 3.4 附核心代码3.4.1 两个action3.4.2 三个reducer 一个整合reducer3.4.3 三个组件 4. 1. 前言
1.1 React中组件通信的其他方式
Reactreact18中组件通信01——props.Reactreact18中组件通信02——消息订阅与发布、取消订阅以及卸载组件时取消订阅.Reactreact18中组件通信03——简单使用 Context 深层传递参数.Reactreact18中组件通信04——redux入门. 而本篇文章的代码改动是在此redux入门文章的基础上改动的所以下面关于redux有疑问的还请看这篇文章。
1.2 介绍React-Redux
1.2.1 简单介绍React-Redux
React-Redux是Redux 官方提供的 React 绑定库。 具有高效且灵活的特性。 react-redux 是一个专为 React 应用开发而设计的基于 Redux 的库提供了一些特定于 React 的功能和组件。它提供了一系列的 API 和组件方便在 React 组件中使用 Redux 进行状态管理。 React-Redux 在概念上非常简单。它订阅 Redux 存储检查组件所需的数据是否已更改并重新渲染组件。react-redux 提供了一些特定于 React 的功能如 connect 函数和 Provider 组件用于连接 Redux 的 store并将状态传递给 React 组件。 React Redux 提供的 Provider / 组件这使得 Redux store 能够在应用的其他地方使用即store只需在入口文件传递一次其他需要store的容器组件中都可以获取。
1.2.2 官网
参考官网 官网地址https://react-redux.js.org/.gitHub上https://github.com/reduxjs/react-redux.Redux 中文官网.React Redux 中文文档. 了解react-redux的其他博客 React-Redux 的历史和实现. 关于下面用到的connect API去官网去官网 https://cn.react-redux.js.org/tutorials/connect.
1.3 安装react-redux
安装命令如下# If you use npm:
npm install react-redux# Or if you use Yarn:
yarn add react-redux2. 简单改写redux的例子
注意这个改写是在redux项目版本的基础上改写的关于redux版本的看下面的 Reactreact18中组件通信04——redux入门.
2.1 提供store
第一步我们需要使得 store 对于我们的应用是可见的。为了做到这个我们使用 React Redux 提供的 API Provider / 去包裹我们的应用。 首先先给改写后的目录结构 然后再看app.js 和 index.js
2.2 连接 Components UI组件修改
2.2.1 连接 Components 先看官网怎么讲解的 先简单写写实现效果后续再优化如下 import CountNumRedux from ../components/CountNumRedux;
import { connect } from react-redux;
import store from ../redux/store//这里ownProps如果用不到的话可以不传可以只传state
const mapStateToProps (state, ownProps) ({// ...依据 state 和 自定义 ownProps 生成 computed data/*** 即状态统一在容器组件中管理* UI组件使用的话直接通过props取就行了这种方式也相当于通过props传递* 如果监听state的变化一有变化就调用并把state通过props传递给UI组件*/count:state// name:麦兜});const mapDispatchToProps ()({// ... 通常是一个充满 action creators 的 objectaddNumber:(number){store.dispatch({ type: INCREMENT, number:number })},reduceNumber:(number){store.dispatch({ type: DECREMENT, number:number })}});// // 1. connect 返回一个接收要包装的组件的新函数
// const connectToStore connect(mapStateToProps, mapDispatchToProps);// // 2. 并且该函数返回连接的包装的组件
// const ConnectedComponent connectToStore(Component);// 通常我们会将两者一步完成像这样
const CountNumContainer connect(mapStateToProps, mapDispatchToProps)(CountNumRedux);export default CountNumContainer;2.2.2 修改UI组件 如下 import { createRef } from react;
// import store from ../redux/store
// import countAction from ../redux/countActionfunction CountNumRedux(props){console.log(props);// const [count,setCount] useState(0);const numberRef createRef();function add(){let number numberRef.current.value;// console.log(typeof number); //string// store.dispatch(countAction.incrementNum(parseInt(number)));props.addNumber(parseInt(number));}function subtract(){let number parseInt(numberRef.current.value);props.reduceNumber(number);}// useEffect((){// store.subscribe((){// console.log(订阅更新,打印2-----,store.getState());// setCount(store.getState());// });// });return(div{/* 当前数字是{count} nbsp;nbsp;nbsp;nbsp;当前数字是{store.getState()} */}当前数值是{props.count}br /浮动数字input typenumber ref{numberRef}/br /br /button onClick{add}点我 加数/button br /br /button onClick{subtract}点我 减数/button/div)
}
export default CountNumRedux;2.2.3 看效果
如下
2.3 连接 Components——优化优化容器组件 主要优化 mapDispatchToProps用封装好的action如下 import CountNumRedux from ../components/CountNumRedux;
import { connect } from react-redux;
// import store from ../redux/store
import {incrementNum,decrementNum} from ../redux/countAction;const mapStateToProps (state) ({count:state});// const mapDispatchToProps ()({
// addNumber:(number){
// store.dispatch(
// { type: INCREMENT, number:number }
// )
// },
// reduceNumber:(number){
// store.dispatch(
// { type: DECREMENT, number:number }
// )
// }
// });/*** 1. dispatchreact-redux 会将dispatch传入所以不用引入store来调了* 2. 引入已经封装好的actioncountAction*/const mapDispatchToProps (dispatch)({addNumber:(number){dispatch( incrementNum(number) )},reduceNumber:(number){dispatch( decrementNum(number) )}
});const CountNumContainer connect(mapStateToProps, mapDispatchToProps)(CountNumRedux);export default CountNumContainer;2.4 优化容器组件可怕的精简
mapDispatchToProps: 此参数可以是一个 function或者一个 object。 上面都是用function写的接下来换成object之后代码真的太少了不妨再看一下官方强调的 精简代码如下/*** 优化2*/
const mapDispatchToProps {//通常是一个充满 action creators 的 objectaddNumber: incrementNum, //addNumber:是通过props传递给UI组件的方法 incrementNum是封装好的action函数reduceNumber: decrementNum
}对比一下
2.5 附代码
关于redux文件下的代码就不贴了因为没改动需要的直接上篇文章就行其他如下 CountNumContainer.jsximport CountNumRedux from ../components/CountNumRedux;
import { connect } from react-redux;
import {incrementNum,decrementNum} from ../redux/countAction;const mapStateToProps (state) ({count:state});const mapDispatchToProps {//通常是一个充满 action creators 的 objectaddNumber: incrementNum, //addNumber:是通过props传递给UI组件的方法 incrementNum是封装好的action函数reduceNumber: decrementNum
}const CountNumContainer connect(mapStateToProps, mapDispatchToProps)(CountNumRedux);export default CountNumContainer;CountNumRedux.jsximport { createRef } from react;function CountNumRedux(props){console.log(props);const numberRef createRef();function add(){let number numberRef.current.value;props.addNumber(parseInt(number));}function subtract(){let number parseInt(numberRef.current.value);props.reduceNumber(number);}return(div{/* 当前数字是{count} nbsp;nbsp;nbsp;nbsp;当前数字是{store.getState()} */}当前数值是{props.count}br /浮动数字input typenumber ref{numberRef}/br /br /button onClick{add}点我 加数/button br /br /button onClick{subtract}点我 减数/button/div)
}
export default CountNumRedux;App.jsimport CountNumContainer from ./container/CountNumContainer.jsxfunction App() {return (div{/* CountNumRedux/ */}CountNumContainer//div);
}export default App;index.jsimport React from react;
import ReactDOM from react-dom/client;
import App from ./App;import store from ./redux/store;
import { Provider } from react-redux;const root ReactDOM.createRoot(document.getElementById(root));
root.render(Provider store{store}App //Provider
);export default root;3. 多reducer实现数据共享
3.1 介绍 combineReducers()函数 随着应用变得越来越复杂可以考虑将 reducer 函数 拆分成多个单独的函数拆分后的每个函数负责独立管理 state 的一部分。 combineReducers 辅助函数的作用是把一个由多个不同 reducer 函数作为 value 的 object合并成一个最终的 reducer 函数然后就可以对这个 reducer 调用 createStore 方法。 合并后的 reducer 可以调用各个子 reducer并把它们返回的结果合并成一个 state 对象。 由 combineReducers() 返回的 state 对象会将传入的每个 reducer 返回的 state 按其传递给 combineReducers() 时对应的 key 进行命名。 示例 rootReducer combineReducers({potato: potatoReducer, tomato: tomatoReducer})
// 这将返回如下的 state 对象
{potato: {// ... potatoes, 和一些其他由 potatoReducer 管理的 state 对象 ...},tomato: {// ... tomatoes, 和一些其他由 tomatoReducer 管理的 state 对象比如说 sauce 属性 ...}
}关于 combineReducers()函数 的介绍来源于官网关于combineReducers()更多讲解可去官网如下 https://cn.redux.js.org/api/combinereducers.
3.2 多reducer整合的例子
3.2.1 想实现的效果
先设计三个组件的渲染如下 这三个组件里的状态都是交给react- redux管理的我们先实现这个无数据共享的然后再实现怎么让组件之间可以数据共享。
3.2.2 项目目录设计结构
如下
3.2.3 将3个reducer整合或者说拆分reducer
关于reducer的拆分可以去官网上面介绍combineReducers()函数时也说了这里就不多说了也可以去官网看拆分reducer逻辑地址如下 拆分 Reducer 逻辑.上面的cat、dog、pet分别对应1个reducer但是创建store的时候只需要一个reducer所以最终需要将这三个reducer函数合并成一个最终的reducer函数给创建store时使用。本项目中怎么使用 combineReducers() 的你现在可以不用知道其他3个reducer长什么样只要他们3个都暴露出了就行所以我这里直接介绍合并如下
3.2.4 每个组件的三个核心文件
3.2.4.1 简单介绍——以cat为例
这里为了看着方便没有抽出常量把UI组件和容器组件整合在了一个文件里所以上面看到的3个模块组件各对应3个核心文件action、reducer、容器组件。下面以cat组件为例进行说明 catAction catReducer: 猫这里只想更改“今日最受欢迎的猫品种“所以这个相对来说是简单的一个action函数就可以了那么如果action设计好了reducer也就可以完善了如下 CatContainer 组件 如下
3.2.4.2 关于dog 和 petPark 的
dog的简单直接看吧如下 dogAction dogReducer: DogContainer 组件 如下 petPark的如下 这个比较简单点因为这个里没有设计状态的改变所以没有对应的action都是初试值如下
3.3 实现数据共享
3.3.1 实现数据共享
现在在上面效果的基础上实现数据共享就很简单了加两行代码的事跟取自己的一样如下 petPark访问其他两个组件的数据 cat访问petPark的数据也是一样的想怎么访问怎么访问因为本来就不在组件内部管理而是react-redux在管理谁用谁取就是了
3.4 附核心代码
3.4.1 两个action catAction 如下
function changeCatKindAction(newKind){return {type: CHANGE_CAT_KIND,kind: newKind}
}export {changeCatKindAction}dogAction 如下
function addDogAction(dogObj){return {type:ADD_DOG,dog:dogObj}
}export {addDogAction}3.4.2 三个reducer 一个整合reducer 前三个如下 const catKindInit 布偶;function catReducer(statecatKindInit, action){switch (action.type) {case CHANGE_CAT_KIND:return action.kind;default:return state;}
}export default catReducer;const dogInit [];
// const dogInit [{dogName:狗狗,dogAge:1}];function dogReducer(state dogInit, action){const {type,dog} action;switch (type) {case ADD_DOG:return [...state,dog];default:return state;}
}export default dogReducer;const adminInit {parkAdmin:素素,parkAdminPhone:176XXXXX};function PetParkReducer(stateadminInit, action){return state; //没有action初始state不需要修改直接返回
}export default PetParkReducer;最终的如下
import catReducer from ./catsReducer;
import dogReducer from ./dogReducer;
import petsParkReducer from ./petsParkReducer;import { combineReducers } from redux;/*** 1. 合并后的 reducer 可以调用各个子 reducer并把它们返回的结果合并成一个 state 对象。 * 2. 由 combineReducers() 返回的 state 对象* 会将传入的每个 reducer 返回的 state 按其传递给 combineReducers() 时对应的 key 进行命名。*/
const rootReducer combineReducers({petParkState: petsParkReducer,dogState: dogReducer,catState: catReducer,
});export default rootReducer;3.4.3 三个组件 CatContainer.jsx 如下 import { connect } from react-redux;
import { useRef } from react;
import {changeCatKindAction} from ../redux/actions/CatAction//1. UI组件
function CatUI(props){const catKindNode useRef();function chagePopularKind(){const newKind catKindNode.current.value;props.changKind(newKind);}return(divh1我是cat组件/h1今日最受欢迎的小猫品种是{props.popularCatKind} br/br/input typetext ref{catKindNode} placeholder请输入今日最受欢迎的/ nbsp;button onClick{chagePopularKind}修改最受欢迎的小猫品种/buttonbr /今日管理员是{props.guanliyuan} br/管理员{props.guanliyuan2.parkAdmin} /div)
}//2. 容器组件function mapStateToProps(state) {return {popularCatKind: state.catState,guanliyuan: state.petParkState.parkAdmin, //可以直接访问其中某个属性guanliyuan2: state.petParkState, //也可以直接访问整个对象}
}const mapDispatchToProps {changKind: changeCatKindAction
}const CatContainer connect(mapStateToProps,mapDispatchToProps)(CatUI);export default CatContainer;DogContainer.jsx 如下 import { useRef } from react;
import { connect } from react-redux
import { addDogAction } from ../redux/actions/DogAction;//1. 定义UI组件
function DogUI(props){// console.log(props);const dogList props.dogListState;//获取狗狗列表信息const dogNameRef useRef();const dogAgeRef useRef();function addParkDog(){const dogName dogNameRef.current.value;const dogAge dogAgeRef.current.value;const dogObj {dogName:dogName,dogAge:dogAge}props.addOneDog(dogObj);}return(divh1我是dog组件/h1 br /1. 狗狗园区地址{props.dogParkAdress} br /br /2. 狗狗姓名input typetext ref{dogNameRef} / br / nbsp;nbsp;nbsp;狗狗年龄input typenumber ref{dogAgeRef}/ nbsp;button onClick{addParkDog}添加狗狗/button br /br /3. 狗狗列表信息ul{dogList.map((dog,index)(li key{index}{dog.dogName}---{dog.dogAge}/li))}/ul/div)
}//2.容器组件 并导出容器组件const mapStateToProps (state){/*** 1. 返回的是一个对象(dog组件 管理自己组件的state)* 2. 语法问题当返回的是一个对象时用一对()括起来否则语法报错*/return({dogListState:state.dogState,dogParkAdress:北京海淀区})
}const mapDispatchToProps {addOneDog: addDogAction
}const DogContainer connect(mapStateToProps,mapDispatchToProps)(DogUI);export default DogContainer;PetParkContainer.jsx 如下 import { connect } from react-redux;
import { useState } from react;//1. UI组件
function PetParkUI(props){console.log(props);const [closeFlag,setCloseFlag] useState(false);console.log(closeFlag);return(divh1我是PetPark组件/h1 1. 管理员{props.parkAdminInfo.parkAdmin} br / nbsp;nbsp;管理员电话{props.parkAdminInfo.parkAdminPhone} br /2. 现有的宠物有{JSON.stringify(props.petKinds)} br /3. 雨天是否闭园{closeFlag ? 是 : 否} br /br /今日猫猫种类王是{props.catKindKing} br /br /今日dog园区有多少条狗狗{props.dogsNum}/div)
}//2.容器组件
const mapStateToProps (state)({parkAdminInfo: state.petParkState,//这个交给react-redux管理的可以共享petKinds: [猫猫,狗狗] ,//这个如果是自身组件用的可以用useState放自身组件上//下面是数据共享的catKindKing: state.catState, //直接取cat组件里的状态dogsNum: state.dogState.length})//connect 的两个参数都是可选的可传可不传
const PetParkContainer connect(mapStateToProps)(PetParkUI);export default PetParkContainer;4.