当前位置: 首页 > news >正文

react-组件进阶

1.目标

能够实用props接收数据
能够实现父子组件之间的通讯
能够实现兄弟组件之间的通讯
能够给组件添加props校验
能够说出生命周期常用的钩子函数
能够知道高阶组件的作用

2.目录

组件通讯介绍
组件的props
组件通讯的三种方式
Context
props深入
组件的生命周期
Render-props和高阶组件

3.react tool

在这里插入图片描述
安装 React Devloper Tools 插件

4.组件通讯介绍

组件是独立且封闭的单元,默认情况下,只能使用组件自己的数据。在组件化过程中,我们将一个完整
的功能拆分成多个组件,以更好的完成整个应用的功能。而在这个过程中,多个组件之间不可避免的要
共享数据。为了实现这些功能,就需要打破组件的独立封闭性,让其与外界沟通。这个过程就是组件通
讯。

5.组件的props

A. 组件是封闭的,要接收外部数据应该通过props来实现
B. props的作用:接收传递给组件的数据
C. 传递数据:给组件标签添加属性
D. 接收数据:函数组件通过参数props接收数据,类组件通过this.props接收数据

function Hello(props) {return <div>接收到的值:{props.name}</div>;
}class Hello1 extends React.Component {constructor() {super();}render() {return <div>接收到的值:{this.props.name}</div>;}
}ReactDOM.createRoot(document.getElementById("root")).render(<React.StrictMode><Hello name="张三"></Hello><Hello1 name="李四"></Hello1></React.StrictMode>
);

5.1 特点

A. 可以给组件传递任意类型的数据
B. props是只读的对象,只能读取属性的值,无法修改对象
C. 注意:使用类组件时,如果写了构造函数,应该将props传递给super(),否则,无法再构造函数中获取
到props!

class Hello2 extends React.Component {constructor(props) {//推荐将props传递给父类构造函数 ???super(props)}
render() {return (<div>接收到的数据:{this.props.age}</div>)}
}
ReactDOM.render(<Hello2 name='rose' age={22}></Hello2>,document.getElementById('root'));

5.2 其他类型数据

class Hello2 extends React.Component {constructor() {//推荐将props传递给父类构造函数super()}
render() {return (<div>接收到的数据:{this.props.age} {this.props.tag}</div>)
}
ReactDOM.render(<Hello2 name='rose' age={22} colors={['red', 'yellow', 'blue']}
fn={() => { console.log('这是一个函数') }} tag={<p>这是一个P标签</p>}></Hello2>,
document.getElementById('root'));

6.组件通讯的三种方式

组件之间的通讯分为3种:
A. 父组件->子组件
B. 子组件->父组件
C. 兄弟组件

6.1 父组件传递数据给子组件

A. 父组件提供要传递的state数据
B. 给子组件标签添加属性,值为state中的数据
C. 子组件中通过props接收父组件中传递的数据

.parent {background-color: skyblue;height: 200px;
}.child {background-color: pink;height: 100px;
}
// 父组件给子组件传值
class Parent61 extends React.Component {state = { lastName: "练" };render() {return (<div className="parent">父组件:{this.state.lastName + "凝"}<Child61 lastName="道济"></Child61></div>);}
}const Child61 = (props) => {return (<div className="child">子组件接受到父组件传的值:{props.lastName}</div>);
};ReactDOM.createRoot(document.getElementById("root")).render(<Parent61></Parent61>
);

6.2 子组件传递数据给父组件

思路:利用回调函数,父组件提供回调,子组件调用,将要传递的数据作为回调函数的参数。
A. 父组件提供一个回调函数(用于接收数据)
B. 将该函数作为属性的值,传递给子组件
C. 子组件通过props调用回调函数
D. 将子组件的数据作为参数传递给回调函数
注意:回调函数里面的this指向问题

// 6.2
class Parent extends React.Component {state = {sonMsg: "",};getChildMsg = (msg) => {this.setState({sonMsg: msg,});};render() {return (<div>子组件传过来的值:{this.state.sonMsg}<Child getMsg={this.getChildMsg}></Child></div>);}
}class Child extends React.Component {state = {sonMsg: "react牛掰!!!",};sendMsg = () => {this.props.getMsg(this.state.sonMsg);};render() {return (<div><button onClick={this.sendMsg}>向父组件传值</button></div>);}
}ReactDOM.createRoot(document.getElementById("root")).render(<Parent></Parent>);

6.3 兄弟传值

A. 将共享数据提升到最近的公共父组件中,由公共父组件管理这个状态
B. 思想:状态提升
C. 公共父组件职责:1.提供共享状态 2.提供操作共享状态的方法
D. 要通过的子组件只需通过props接收状态或操作状态的方法

class Parent63 extends React.Component {// 提供公共状态state = {count: 0,};// 提供修改状态的方法onIncrement = () => {this.setState({count: this.state.count + 1,});};render() {return (<div><Child631 count={this.state.count}></Child631><Child632 onIncrement={this.onIncrement}></Child632></div>);}
}
const Child631 = (props) => {return <div>计数器{props.count}</div>;
};
const Child632 = (props) => {return <button onClick={() => props.onIncrement()}>+1</button>;
};ReactDOM.createRoot(document.getElementById("root")).render(<Parent63></Parent63>
);

6.4 context

思考:App组件要传递数据给Child组件,该如何处理
A. 处理方式:使用props一层层组件往下传递(繁琐)
B. 更好的姿势:使用Context
C. 作用:跨组件传递数据(比如:主题、语言等)
在这里插入图片描述

6.4.1 使用步骤

A. 调用React.createContext()创建Provider(提供数据)和Consumer(消费数据)两个组件。
B.使用Provider组件作为父节点
C. 设置value属性,表示要传递的数据
D. 调用Consumer组件传递数据

.app64{
background-color: red;
padding:20px;
}
.node64{
background-color: yellow;
padding:20px;
}
.subNode64{
background-color: green;
padding:20px;
}
.child64{
background-color: purple;
padding: 20px;
}
// 创建context得到两个组件
const { Provider, Consumer } = React.createContext();class App64 extends React.Component {render() {return (<div><Provider value={"hello"}><div className="app64"><Node64></Node64></div></Provider></div>);}
}const Node64 = () => {return (<div className="node64"><SubNode64></SubNode64></div>);
};const SubNode64 = () => {return (<div className="subNode64"><Child64></Child64></div>);
};const Child64 = () => {return (<div className="child64"><Consumer>{(data) => <span>我是子节点{data}</span>}</Consumer></div>);
};ReactDOM.createRoot(document.getElementById("root")).render(<App64></App64>);

在这里插入图片描述

6.4.2 总结

A. 如果两个组件是远方亲戚(比如,嵌套多层)可以使用Context实现组件通讯
B. Context提供了两个组件:Provider和Consumer
C. Provider组件:用来提供数据
D. Consumer组件:用来消费数据

7.props深入

7.1 children属性

A. children属性:表示组件标签的子节点。当组件标签有子节点时,props就会有该属性
B. children属性与普通的props一样,值可以是任意值(文本、React元素、组件,甚至是函数)

const App1 = (props) => {console.log(props);return (<div><h1>组件标签的子节点:</h1>{props.children}</div>);
};ReactDOM.createRoot(document.getElementById("root")).render(<App1><p>我是p标签</p>{/* {() => {console.log(123);}} */}</App1>
);

7.2 props校验

A. 对于组件来说,props是外来的,无法保证组件使用者传入什么格式的数据
B. 如果传入的数据格式不对,可能会导致组件内部报错
C. 关键问题:组件的使用者不知道明确的错误原因

function App72(props) {const list = props.list;const lis = list.map((item, index) => <li key={index}>{item}</li>);return <ul>{lis}</ul>;
}ReactDOM.createRoot(document.getElementById("root")).render(<App72 list={19}></App72>
);

D.props校验:允许在创建组件的时候,就指定props的类型、格式等
E. 作用:捕获使用组件时因为props导致的错误,给出明确的错误提示,增加组件的健壮性

7.2.1 使用步骤

A. 安装包prop-types(yarn add prop-types/npm i prop-types)
B. 导入prop-types包
C. 使用组件名.propTypes={}来给组件的props添加校验规则
D. 校验规则通过PropTypes对象来指定
在这里插入图片描述

import PropTypes from "prop-types";
function App721(props) {const list = props.list;const lis = list.map((item, index) => <li key={index}>{item}</li>);return <ul>{lis}</ul>;
}
App721.propTypes = {//约定list属性为array类型//如果类型不对,则报错明确错误,便于分析错误原因list: PropTypes.array,
};ReactDOM.createRoot(document.getElementById("root")).render(<App721 list={19}></App721>
);

7.3 props的默认值

A. 场景:分页组件->每页显示条数
B. 作用:给props设定默认值,在未传入props时生效

class App73 extends React.Component {render() {return (<div>此处展示props默认值:{this.props.age} {this.props.gender}</div>);}
}App73.defaultProps = {age: 18,gender: "男",
};ReactDOM.createRoot(document.getElementById("root")).render(<App73 name="zs"></App73>
);

8.组件的生命周期

8.1 组件的生命周期概述

A. 意义:组件的生命周期有助于理解组件的运行方式,完成更复杂的组件功能,分析组件错误原因等
B. 组件的生命周期:组件从被创建到挂载到页面中运行,再到组件不用时卸载的过程
C. 生命周期的每个阶段总是伴随着一些方法调用,这些方法就是生命周期的钩子函数。
D. 钩子函数的作用:为开发人员再不同阶段操作组件提供了时机
E. 只有类组件才有生命周期

8.2 生命周期的三个阶段

A. 每个阶段的执行时机
B. 每个阶段钩子函数的执行顺序
C. 每个阶段钩子函数的作用
在这里插入图片描述

8.2.1 创建时(挂载阶段)

A. 执行时机:组件创建时(页面加载时)
B. 执行顺序:
在这里插入图片描述constructor:创建组件时,最先执行。初始化state和为事件处理程序绑定this
render:每次组件渲染都会触发,渲染ui(注意:不能调用setState)
componentDidMount:组件挂载(完成DOM渲染)后,发送网络请求,DOM操作

class App821 extends React.Component {constructor(props) {super(props);// 初始化数据this.state = {count: 0,};// 主要处理this指向问题console.log("生命周期钩子函数:constructor");const title = document.getElementById("h1");console.log("constructor中的DOM为" + title); // null,获取不到DOM}// 进行DOM操作// 发送ajax请求,获取远程数据componentDidMount() {const title = document.getElementById("h1");console.log("componentDidMount中的DOM为" + title); // 获取到了}render() {// 不要在render中调用setState// this.setState({//   count: 1,// });console.log("生命周期钩子函数:render");return (<div><h1 id="h1">统计豆豆被打的次数:</h1><button>打豆豆</button></div>);}
}ReactDOM.createRoot(document.getElementById("root")).render(<App821></App821>);

8.2.2 更新时(更新阶段)

A. 执行时机:1.setState() 2.forceUpdate() 3.组件接收到新的props
B. 说明:以上三者任意一种变化,组件就会重新渲染
C. 执行顺序:
在这里插入图片描述
render():每次组件渲染都会触发,渲染UI(在挂载阶段是同一个render)
componentDidUpdate():组件更新(完成DOM渲染)后,发送网络请求,DOM操作(注意:如果要
setState()必须放在一个if条件中)

class App822 extends React.Component {constructor(props) {super(props);this.state = {count: 0,};}handleClick = () => {this.setState({count: this.state.count + 1,});};render() {return (<div><Counter822 count={this.state.count}></Counter822><button onClick={this.handleClick}>打豆豆</button></div>);}
}class Counter822 extends React.Component {render() {console.log("子组件-生命周期钩子函数:render()");return (<div><h1 id="title">打豆豆的数量:{this.props.count}</h1></div>);}componentDidUpdate(prevProps) {console.log("子组件-生命周期钩子函数:componentDidUpdate()");//获取domconst title = document.getElementById("title");console.log(title.innerHTML);console.log("前一状态的props值:",prevProps,"当前状态的props值:",this.props);}
}ReactDOM.createRoot(document.getElementById("root")).render(<App822></App822>);

8.2.3 卸载时

A.执行时机:组件从页面中消失
componentWillUnmount:组件卸载(从页面消失),执行清理工作

class App823 extends React.Component {constructor(props) {super(props);// 初始化数据this.state = {count: 0,};}handleClick = () => {this.setState({count: this.state.count + 1,});};render() {console.log("生命周期钩子函数:render()");return (<div>{this.state.count > 3 ? (<h1>豆豆被打死了</h1>) : (<Count823 count={this.state.count}></Count823>)}<button onClick={this.handleClick}>打豆豆</button></div>);}
}
class Count823 extends React.Component {render() {console.log("子组件-生命周期钩子函数:render()");return <h1 id="title">豆豆被打的次数:{this.props.count}</h1>;}componentDidMount() {console.log("子组件-生命周期钩子函数:componentDidMount()"); // 创建时钩子函数,只在创建时执行一次this.timerId = setInterval(() => {console.log("定时器正在执行中~~~~~~~~");}, 500);}componentWillUnmount() {console.log("子组件-生命周期钩子函数:componentWillUnmount()");clearInterval(this.timerId);}
}ReactDOM.createRoot(document.getElementById("root")).render(<App823></App823>);

9.render-props和高阶组件

9.1 react组件复用概述

A. 思考:如果两个组件中的部分功能相似或相同,该如何处理?
B. 处理方式:复用相似的功能(联想函数封装)
C. 复用什么?1.state 2.操作state的方法(组件状态逻辑)
D. 两种方式:1.render props模式 2.高阶组件(HOC)
E. 注意:这两种方式不是新的API,而是利用React自身特点的编码技巧,演化而成的固定模式(写法)

9.2 render props 模式

9.2.1 思路分析

A. 思路:将要复用的state和操作state的方法封装到一个组件中
B. 问题1:如何拿到该组件中复用的state
C. 在使用组件时,添加一个值为函数的prop,通过函数参数获取(需要组件内部实现)
D. 问题2:如何渲染任意的UI?
E. 使用该函数的返回值作为要渲染的UI内容(需要组件内部实现)

9.2.2 使用步骤

A. 创建Mouse组件,在组件中提供复用的状态逻辑代码(1.状态 2.操作状态的方法)
B. 将要复用的状态作为props.render(state)方法的参数,暴露到组件外部
C. 使用props.render()的放回置作为要渲染的内容
9.2render_props.js

import React from "react";
import ReactDOM from "react-dom/client";
import PropTypes from "prop-types";//创建Mouse组件
class Mouse extends React.Component {// 鼠标位置state = {x: 0,y: 0,};//鼠标移动事件的事件处理程序handleMouse = (e) => {this.setState({x: e.clientX,y: e.clientY,});};// 组件被挂载到页面后调用--监听鼠标移动事件componentDidMount() {window.addEventListener("mousemove", this.handleMouse);}render() {return this.props.render(this.state);}
}
class App92 extends React.Component {render() {return (<div><h1>render props模式</h1><Mouserender={(mouse) => {return (<h1>鼠标坐标:{mouse.x}:{mouse.y}</h1>);}}></Mouse></div>);}
}export default App92;

index.js

import App92 from "./92render_props";
ReactDOM.createRoot(document.getElementById("root")).render(<App92></App92>);

9.2.3 mouse组件的复用

A. Mouse组件负责:封装复用的状态逻辑代码(1.状态 2.操作状态的方法)
B. 状态:鼠标坐标(x,y)
C. 操作状态的方法:鼠标移动事件
D. 传入的render prop负责:使用复用的状态来渲染UI结构

import React from "react";
import ReactDOM from "react-dom/client";
import PropTypes from "prop-types";// 导入图片
import img from "./logo192.png";//创建Mouse组件
class Mouse extends React.Component {// 鼠标位置state = {x: 0,y: 0,};//鼠标移动事件的事件处理程序handleMouse = (e) => {this.setState({x: e.clientX,y: e.clientY,});};// 组件被挂载到页面后调用--监听鼠标移动事件componentDidMount() {window.addEventListener("mousemove", this.handleMouse);}render() {return this.props.render(this.state);}
}
class App92 extends React.Component {render() {return (<div><h1>render props模式</h1>{/* 鼠标位置 */}<Mouserender={(mouse) => {return (<h1>鼠标坐标:{mouse.x}:{mouse.y}</h1>);}}></Mouse>{/* 图片 */}<Mouserender={(mouse) => {return (<imgwidth="50"src={img}alt="鼠标图片"style={{position: "absolute",top: mouse.y,left: mouse.x,cursor: "none",}}></img>);}}></Mouse></div>);}
}export default App92;

9.2.4 children代替render属性

A. 注意:并不是该模式叫render props就必须使用名为render的prop,实际上可以使用任意名称的prop
B. 把prop是一个函数并且告诉组件要渲染什么内容的技术叫做:render props模式
C. 推荐:使用children代替render属性

import React from "react";
import ReactDOM from "react-dom/client";
import PropTypes from "prop-types";// 导入图片
import img from "./logo192.png";//创建Mouse组件
class Mouse extends React.Component {// 鼠标位置state = {x: 0,y: 0,};//鼠标移动事件的事件处理程序handleMouse = (e) => {this.setState({x: e.clientX,y: e.clientY,});};// 组件被挂载到页面后调用--监听鼠标移动事件componentDidMount() {window.addEventListener("mousemove", this.handleMouse);}render() {// return this.props.render(this.state);return this.props.children(this.state);}
}
class App92 extends React.Component {render() {return (<div><h1>render props模式</h1>{/* 鼠标位置 */}{/* <Mouserender={(mouse) => {return (<h1>鼠标坐标:{mouse.x}:{mouse.y}</h1>);}}></Mouse> */}{/* 图片 */}{/* <Mouserender={(mouse) => {return (<imgwidth="50"src={img}alt="鼠标图片"style={{position: "absolute",top: mouse.y,left: mouse.x,cursor: "none",}}></img>);}}></Mouse> */}{/* children版本 */}<Mouse>{(mouse) => {return (<h1>鼠标位置:{mouse.x}:{mouse.y}</h1>);}}</Mouse>{/* Mouse组件复用 */}<Mouse>{(mouse) => {return (<imgsrc={img}alt="react"width={100}style={{position: "absolute",top: mouse.y - 50,left: mouse.x - 50,}}></img>);}}</Mouse></div>);}
}export default App92;

9.2.5 代码优化

A. 推荐:给render props 模式添加props校验
B. 应该在组件卸载时接触mousemove事件绑定

import React from "react";
import ReactDOM from "react-dom/client";
import PropTypes from "prop-types";// 导入图片
import img from "./logo192.png";//创建Mouse组件
class Mouse extends React.Component {// 鼠标位置state = {x: 0,y: 0,};//鼠标移动事件的事件处理程序handleMouse = (e) => {this.setState({x: e.clientX,y: e.clientY,});};// 组件被挂载到页面后调用--监听鼠标移动事件componentDidMount() {window.addEventListener("mousemove", this.handleMouse);}render() {// return this.props.render(this.state);return this.props.children(this.state);}// 推荐:在组件卸载时移除事件绑定componentWillUnmount() {window.removeEventListener("mousemove", this.handleMouse);}
}
// 添加校验
Mouse.propTypes = {children: PropTypes.func.isRequired,
};class App92 extends React.Component {render() {return (<div><h1>render props模式</h1>{/* 鼠标位置 */}{/* <Mouserender={(mouse) => {return (<h1>鼠标坐标:{mouse.x}:{mouse.y}</h1>);}}></Mouse> */}{/* 图片 */}{/* <Mouserender={(mouse) => {return (<imgwidth="50"src={img}alt="鼠标图片"style={{position: "absolute",top: mouse.y,left: mouse.x,cursor: "none",}}></img>);}}></Mouse> */}{/* children版本 */}<Mouse>{(mouse) => {return (<h1>鼠标位置:{mouse.x}:{mouse.y}</h1>);}}</Mouse>{/* Mouse组件复用 */}<Mouse>{(mouse) => {return (<imgsrc={img}alt="react"width={100}style={{position: "absolute",top: mouse.y - 50,left: mouse.x - 50,}}></img>);}}</Mouse></div>);}
}export default App92;

9.3 高阶组件

9.3.1 概述

A. 目的:实现状态逻辑复用
B. 采用包装(装饰)模式,比如说:手机壳
C. 手机:获取保护功能
D. 手机壳:提供保护功能
E. 高阶组件就相当于手机壳,通过包装组件,增强组件功能

9.3.2 思路分析

A. 高阶组件(HOC,Higher-Order Component)是一个函数,接收要包装的组件,返回增强后的组件
B. 高阶组件内部创建一个类组件,在这个类组件中提供复用的状态逻辑代码,通过prop将复用的状态传
递给被包装组件WrappendComponent

9.3.3 使用步骤

A. 创建一个函数,名称约定以with开头
B. 指定函数参数,参数应该以大写字母开头(作为要渲染的组件)
C. 在函数内部创建一个类组件,提供复用的状态逻辑代码,并返回
D. 在该组件中,渲染参数组件,同时将状态通过prop传递给参数组件
E. 调用该高阶组件,传入要增强的组件,通过返回值拿到增强后的组件,并将其渲染到页面中
9.3 gjzj.js

import React from "react";
import ReactDOM from "react-dom/client";
import PropTypes from "prop-types";// 导入图片
import img from "./logo192.png";//创建高阶组件
function WithMouse(WrappendComponent) {//该组件提供复用的状态逻辑class Mouse extends React.Component {state = {x: 0,y: 0,};handleMouse = (e) => {this.setState({x: e.clientX,y: e.clientY,});};// 监听鼠标移动事件componentDidMount() {window.addEventListener("mousemove", this.handleMouse);}//推荐:在组件卸载时移除事件绑定componentWillUnmount() {window.removeEventListener("mousemove", this.handleMouse);}// 渲染被包装的组件,并传递复用的状态逻辑render() {return <WrappendComponent {...this.state}></WrappendComponent>;}}return Mouse;
}// 普通测试
const Position = (props) => {return (<h1>【x:{props.x},y:{props.y}</h1>);
};const Img = (props) => {return (<imgsrc={img}alt="图片"width={50}style={{ position: "absolute", top: props.y, left: props.x }}></img>);
};// 获取增强后组件
const MousePosition = WithMouse(Position);
const MouseImg = WithMouse(Img);class App93 extends React.Component {render() {return (<div>高阶组件:<MousePosition></MousePosition><MouseImg></MouseImg></div>);}
}export default App93;
import App93 from "./93gjzj";
ReactDOM.createRoot(document.getElementById("root")).render(<App93></App93>);

9.3.4 设置displayName

A. 使用高阶组件存在的问题:得到的两个组件名称相同
B. 原因:默认情况下,React使用组件名称作为displayName
C. 解决方式:为高阶组件设置displayName便于调试时区分不同的组件
D. displayName的作用:用于设置调试信息(React Developer Tools信息)
E. 设置方式:

import React from "react";
import ReactDOM from "react-dom/client";
import PropTypes from "prop-types";// 导入图片
import img from "./logo192.png";//创建高阶组件
function WithMouse(WrappendComponent) {//该组件提供复用的状态逻辑class Mouse extends React.Component {state = {x: 0,y: 0,};handleMouse = (e) => {this.setState({x: e.clientX,y: e.clientY,});};// 监听鼠标移动事件componentDidMount() {window.addEventListener("mousemove", this.handleMouse);}//推荐:在组件卸载时移除事件绑定componentWillUnmount() {window.removeEventListener("mousemove", this.handleMouse);}// 渲染被包装的组件,并传递复用的状态逻辑render() {return <WrappendComponent {...this.state}></WrappendComponent>;}}//设置displayMouse.displayName = `WithMouse${getDisplayName(WrappendComponent)}`;return Mouse;
}
function getDisplayName(WrappendComponent) {return WrappendComponent.displayName || WrappendComponent.name || "Component";
}// 普通测试
const Position = (props) => {return (<h1>【x:{props.x},y:{props.y}</h1>);
};const Img = (props) => {return (<imgsrc={img}alt="图片"width={50}style={{ position: "absolute", top: props.y, left: props.x }}></img>);
};// 获取增强后组件
const MousePosition = WithMouse(Position);
const MouseImg = WithMouse(Img);class App93 extends React.Component {render() {return (<div>高阶组件:<MousePosition></MousePosition><MouseImg></MouseImg></div>);}
}export default App93;

9.3.5 传递props

A. 问题:props丢失
B. 原因:高阶组件没有往下传递props
C. 解决方式:渲染WrappedComponent时,将state和this.props一起传递给组件
D. 传递方式:

import React from "react";
import ReactDOM from "react-dom/client";
import PropTypes from "prop-types";// 导入图片
import img from "./logo192.png";//创建高阶组件
function WithMouse(WrappendComponent) {//该组件提供复用的状态逻辑class Mouse extends React.Component {state = {x: 0,y: 0,};handleMouse = (e) => {this.setState({x: e.clientX,y: e.clientY,});};// 监听鼠标移动事件componentDidMount() {window.addEventListener("mousemove", this.handleMouse);}//推荐:在组件卸载时移除事件绑定componentWillUnmount() {window.removeEventListener("mousemove", this.handleMouse);}// 渲染被包装的组件,并传递复用的状态逻辑render() {return (<WrappendComponent {...this.state} {...this.props}></WrappendComponent>);}}//设置displayMouse.displayName = `WithMouse${getDisplayName(WrappendComponent)}`;return Mouse;
}
function getDisplayName(WrappendComponent) {return WrappendComponent.displayName || WrappendComponent.name || "Component";
}// 普通测试
const Position = (props) => {return (<h1>【x:{props.x},y:{props.y} {console.log(props)}</h1>);
};const Img = (props) => {return (<imgsrc={img}alt="图片"width={50}style={{ position: "absolute", top: props.y, left: props.x }}></img>);
};// 获取增强后组件
const MousePosition = WithMouse(Position);
const MouseImg = WithMouse(Img);class App93 extends React.Component {render() {return (<div>高阶组件:<MousePosition></MousePosition><MouseImg></MouseImg></div>);}
}export default App93;

相关文章:

react-组件进阶

1.目标 能够实用props接收数据 能够实现父子组件之间的通讯 能够实现兄弟组件之间的通讯 能够给组件添加props校验 能够说出生命周期常用的钩子函数 能够知道高阶组件的作用 2.目录 组件通讯介绍 组件的props 组件通讯的三种方式 Context props深入 组件的生命周期 Render-p…...

企业有了ERP,为什么还要上BI?

在我们以往和企业的沟通过程中&#xff0c;我们发现还是有相当多的一部分企业对于商业智能 BI 了解不多&#xff0c;或者对商业智能 BI 的理解仅停留在花花绿绿的可视化页面上&#xff0c;要么就是提出以下类似问题&#xff1a; 财务部门&#xff1a;BI 的财务分析指标也就是三…...

P1331 海战

难度&#xff1a;普及- 题目背景 在峰会期间&#xff0c;武装部队得处于高度戒备。警察将监视每一条大街&#xff0c;军队将保卫建筑物&#xff0c;领空将布满了 F-2003 飞机。 此外&#xff0c;巡洋船只和舰队将被派去保护海岸线。不幸的是&#xff0c;因为种种原因&#x…...

Orange3数据预处理(索引选择器组件)

组件描述 数据行即使在某些或全部原始变量被来自原始变量的计算变量替换时&#xff0c;也保持其身份。 此小部件获取两个数据表&#xff08;“数据”和“数据子集”&#xff09;&#xff0c;它们可以追溯到同一来源。基于行身份而非实际数据&#xff0c;它会从“数据”中选择所…...

Python实现时间序列分析进行平稳性检验(ADF和KPSS)和差分去趋势(adfuller和kpss算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 时间序列分析中的平稳性检验是评估一个时间序列是否具有稳定的均值和方差。在经济学、金融学以及其他诸…...

代码随想录 Leetcode494. 目标和

题目&#xff1a; 代码(首刷看解析 2024年2月26日&#xff09; 思路&#xff1a;根据题意&#xff0c;设两个背包&#xff0c;packageA存放前面是""的数字之和&#xff0c;packageB存放前面是“-”的数字之和 则sum packageA packageB; target packageA - packag…...

【5G NR】【一文读懂系列】移动通讯中使用的信道编解码技术-NR编解码LDPC和Polar概述(一)

目录 NR LDPC和Polar编码技术概述 LDPC&#xff08;低密度奇偶校验码&#xff09; LDPC 工作原理 LDPC 应用场景&#xff1a; LDPC 与其他编码技术相比的优势&#xff1a; Polar 极化码 Polar 工作原理 Polar 应用场景&#xff1a; Polar 与其他编码技术相比的优势&am…...

代码库管理工具Git介绍

阅读本文同时请参阅-----免费的Git图形界面工具sourceTree介绍 Git是一个分布式版本控制系统&#xff0c;它可以帮助开发者跟踪和管理代码历史。Git的命令行工具是使用Git的核心方式&#xff0c;虽然它可能看起来有些复杂&#xff0c;但是一旦掌握了基本命令&#xff0c;你…...

【长期更新】游戏开发中可能会用到的数学小工具

从一个向量生成一组正交基 https://graphics.pixar.com/library/OrthonormalB/paper.pdf...

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的活体人脸检测系统(Python+PySide6界面+训练代码)

摘要&#xff1a;本篇博客详细讲述了如何利用深度学习构建一个活体人脸检测系统&#xff0c;并且提供了完整的实现代码。该系统基于强大的YOLOv8算法&#xff0c;并进行了与前代算法YOLOv7、YOLOv6、YOLOv5的细致对比&#xff0c;展示了其在图像、视频、实时视频流和批量文件处…...

亚信安慧AntDB助力全链路实时化

实时数据平台&#xff0c;快速实现企业全链路实时化 引入数据仓库、数据挖掘、HTAP等先进理念&#xff0c;通过实时数据应用平台来装载庞大的信息量&#xff0c;进行实时分析处理&#xff0c;克服数据处理过程中的困难&#xff0c;是当下各企事业单位、互联网、金融&#xff0c…...

C#进阶——反射、特性

反射 特性...

UE5 C++ 发射子弹发射(Projectile)

一.相关蓝图的练习&#xff0c;在我之前的文章中射击子弹案例-CSDN博客 本篇使用C实现 1.创建C类 MyBullet,在MyBullet.h中包含相关头文件 #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "Components/StaticMeshComponent.…...

【蓝牙协议栈】【蓝牙分析工具】Ellisys 分析HCI Log和btsnoop Log

1.Ellisys 介绍 Ellisys 的 air log sniffer设备要二三十万,一般不是专业开发蓝牙的估计不会选择使用这个工具,但是即使我们不买这个设备,安装了 Ellisys 的工具也可以看 btsnoop 的,下面我就一步一步教你通过 Ellisys 来打开 btsnoop。 1.1 首先打开 APP(Ellisys 不能直…...

亚信安慧AntDB数据库与流式处理的有机融合

流式处理的概念 2001年9月11日&#xff0c;美国世贸大楼被袭击&#xff0c;美国国防部第一次将“主动预警”纳入国防的宏观战略规划。而IBM作为当时全球最大的IT公司&#xff0c;承担了大量基础支撑软件研发的任务。其中2009年正式发布的IBM InfoSphere Streams&#xff0c;就是…...

神经网络系列---权重初始化方法

文章目录 权重初始化方法Xavier初始化&#xff08;Xavier initialization&#xff09;Kaiming初始化&#xff0c;也称为He初始化LeCun 初始化正态分布与均匀分布Orthogonal InitializationSparse Initializationn_in和n_out代码实现 权重初始化方法 Xavier初始化&#xff08;X…...

【重要公告】BSV区块链协会宣布将启动多项动态安全增强措施

​​发表时间&#xff1a;2024年2月16日 2024年2月16日&#xff0c;瑞士楚格 - BSV区块链协议的管理机构BSV区块链协会&#xff08;以下简称“BSV协会”&#xff09;宣布对其运营模式实施全新的安全架构&#xff0c;其中包括引入网络访问规则和数字资产找回协议&#xff0c;以及…...

软件设计模式之访问者模式(Visitor Pattern)

访问者模式是一种行为型设计模式&#xff0c;它允许你定义一系列操作&#xff0c;这些操作可以应用于对象结构中的元素&#xff0c;而不改变这些元素的类。通过这种方式&#xff0c;可以在不改变各个元素的类的情况下&#xff0c;增加新的操作。 1. 何时使用访问者模式&#x…...

【MySQL】主从同步原理、分库分表

主从同步原理 1. 主从同步原理 MySQL 经常先把命令拷入硬盘的日志&#xff0c;再执行日志的命令&#xff0c;这样的好处&#xff1a; 日志的位置固定&#xff0c;拷入硬盘的开销不大&#xff1b;将命令先准备好&#xff0c;而不是边读边执行&#xff0c;性能更好&#xff0c;…...

uniapp如何实现关闭前面指定数目页面

需求 &#xff1a; 路由从 页面A -> 页面B-> 页面C-> 页面D 我希望在 页面C跳到页面CD 后 在页面D 中 点击返回&#xff08;物理键或是代码返回&#xff09;&#xff0c;直接返回到A,而不是页面C 所以我需要把BC页面给销毁掉 以下是我的实现思路&#xff0c;在h…...

19c补丁后oracle属主变化,导致不能识别磁盘组

补丁后服务器重启&#xff0c;数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后&#xff0c;存在与用户组权限相关的问题。具体表现为&#xff0c;Oracle 实例的运行用户&#xff08;oracle&#xff09;和集…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结&#xff1a; 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析&#xff1a; 实际业务去理解体会统一注…...

DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”

目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

C#学习第29天:表达式树(Expression Trees)

目录 什么是表达式树&#xff1f; 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持&#xff1a; 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...

【Linux系统】Linux环境变量:系统配置的隐形指挥官

。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量&#xff1a;setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...

MySQL 主从同步异常处理

阅读原文&#xff1a;https://www.xiaozaoshu.top/articles/mysql-m-s-update-pk MySQL 做双主&#xff0c;遇到的这个错误&#xff1a; Could not execute Update_rows event on table ... Error_code: 1032是 MySQL 主从复制时的经典错误之一&#xff0c;通常表示&#xff…...

redis和redission的区别

Redis 和 Redisson 是两个密切相关但又本质不同的技术&#xff0c;它们扮演着完全不同的角色&#xff1a; Redis: 内存数据库/数据结构存储 本质&#xff1a; 它是一个开源的、高性能的、基于内存的 键值存储数据库。它也可以将数据持久化到磁盘。 核心功能&#xff1a; 提供丰…...

《Docker》架构

文章目录 架构模式单机架构应用数据分离架构应用服务器集群架构读写分离/主从分离架构冷热分离架构垂直分库架构微服务架构容器编排架构什么是容器&#xff0c;docker&#xff0c;镜像&#xff0c;k8s 架构模式 单机架构 单机架构其实就是应用服务器和单机服务器都部署在同一…...