根据Vue对比来深入学习React 下 props 组件传值 插槽 样式操作 hooks 高阶组件 性能优化

文章目录
- 函数组件的特点
- props
- 组件间的传值
- 父传子看上例
- 子传父
- 兄弟组件传值
- 祖先组件传值
- 插槽
- 基础插槽
- 具名插槽
- 作用域插槽
- 样式操作
- **CSS Modules**
- 生命周期
- useRef
- 常用hook
- useState
- useEffect
- useContext
- useReducer
- useMemo
- useCallback
- 高阶组件
- 什么时候使用
- react性能问题和优化
- React的时间切片
- fiber
- 避免父组件数据导致子组件更新
函数组件的特点
- 函数组件没有生命周期
- 函数组件没有this
- 函数组件通过hook来完成各种操作
- 函数组件本身的函数体相当于render函数
- props在函数的第一个参数接受
props
props是react中的核心
在react中,一切写在组件上的属性和子节点都被规划为了props。
所以props是react很多功能的根本。父子传值,插槽全都是基于props,不像Vue有事件监听,emit,专门的插槽这一类东西
//也可以给默认值
function Avatar({ person, size= 100 }) {return (<imgclassName="avatar"src={getImageUrl(person)}alt={person.name}width={size}height={size}/>);
}export default function Profile() {return (<div><Avatarsize={100}person={{ name: 'Katsuko Saruhashi', imageId: 'YfeOqp2'}}/></div>);
}
组件间的传值
父传子看上例
子传父
子组件可以通过回调函数将数据传递回父组件。没有Vue中的emit和expose方法
// 子组件const ChildComponent = ({ onSendData }) => {return <button onClick={() => onSendData("Hello from Child!")}>Send Data</button>;};// 父组件const ParentComponent = () => {const handleData = (data) => {console.log(data);};return <ChildComponent onSendData={handleData} />;};
兄弟组件传值
与Vue相同 都是通过父组件作为中介来传递数据。
// 第一个兄弟组件const BrotherOne = ({ onSendData }) => {return <button onClick={() => onSendData("Data from Brother One")}>Send Data</button>;};// 第二个兄弟组件const BrotherTwo = ({ data }) => {return <h1>{data}</h1>;};// 父组件const ParentComponent = () => {const [data, setData] = React.useState("");const handleDataChange = (newData) => {setData(newData);};return (<div><BrotherOne onSendData={handleDataChange} /><BrotherTwo data={data} /></div>);};
祖先组件传值
import React, { createContext, useContext, useState } from 'react';JJ// 创建 Contextconst MyContext = createContext();// 提供者组件const MyProvider = ({ children }) => {const [value, setValue] = useState("Hello from Context!");return (<MyContext.Provider value={{ value, setValue }}>J{children}</MyContext.Provider>);};// 使用 Context 的子组件const ChildComponent = () => {const { value } = useContext(MyContext);return <h1>{value}</h1>;};// 父组件const ParentComponent = () => {return (<MyProvider><ChildComponent /></MyProvider>);};
插槽
在 React 中,虽然没有 Vue 的插槽(slot)具名插槽 作用域插槽,但是可以实现
插槽本质上讲就是子组件的html内容需要父组件传入,在jsx的加持下,我可以把html像普通的字符串,数字一样传递,所以插槽只需要直接作为props传入就行
基础插槽
在基础插槽中,我们可以使用 children prop 来接收父组件传递的内容
import React from 'react';// 容器组件,支持基础插槽const Container = ({ children }) => {return (<div className="container"><h2>Container Header</h2><div className="content">{children}</div></div>);};// 使用容器组件const App = () => {return (<Container><p>This is the content inside the container.</p></Container>);};
export default App;
具名插槽
可以通过将不同的 props 传递给子组件来实现。我们可以使用标准的 JSX 语法来实现具名插槽
import React from 'react';
// 容器组件,支持具名插槽const Container = ({ header, footer, children }) => {return (<div className="container"><div className="header">{header}</div><div className="content">{children}</div><div className="footer">{footer}</div></div>);};// 使用容器组件const App = () => {return (<Containerheader={<h1>This is the Header</h1>}footer={<h2>This is the Footer</h2>}><p>This is the main content area.</p></Container>
);
};
export default App;
作用域插槽
允许我们将数据传递到子组件,使得父组件可以控制子组件的渲染。我们可以通过传递一个函数作为 prop 来实现
import React from 'react';
// 容器组件,支持作用域插槽const ListContainer = ({ items, renderItem }) => {return (<ul>{items.map(item => (<li key={item.id}>{renderItem(item)}</li>))}</ul>);};
// 使用容器组件const App = () => {const items = [{ id: 1, text: 'Item 1' },{ id: 2, text: 'Item 2' },{ id: 3, text: 'Item 3' }];const renderItem = (item) => <span>{item.text}</span>;return (<ListContainer items={items} renderItem={renderItem} />);};export default App;
样式操作
class类名设值:必须写为className 类名和样式写在css文件里 必须接受一个字符串
style内联:不能像原生一样写成字符串,必须写成对象
import React from 'react';import './styles.css'; // 这里引入你的 CSS 文件const MyComponent = ({ className, style }) => {return (<div className={className} style={style}>Hello, World!</div>);};// 使用组件const App = () => {const customStyle = {color: 'blue',fontSize: '20px',backgroundColor: 'lightgray',};return (<MyComponentclassName="my-custom-class" // 在 CSS 文件中定义的类名style={customStyle} // 使用对象形式的内联样式/>);};export default App;
CSS Modules
CSS Modules 提供了局部作用域的 CSS,避免类名冲突。
//styles.module.css
.myCustomClass { color: blue; font-size: 20px; padding: 10px; background-color: lightgray; }import styles from './styles.module.css';
const MyComponent = () => { return <div className={
styles.myCustomClass}>
Hello, World!
</div>;};
生命周期
在 React 函数组件中,没有传统的生命周期方法 ,React 通过 Hooks 提供了类似的功能,允许你在不同的阶段执行副作用。
import React, { useEffect } from 'react';const MyComponent = () => {useEffect(() => {// 组件挂载时执行return () => {// 组件卸载时执行};}, []); // 空数组表示只在挂载和卸载时执行return <div>Hello, World!</div>;};
useRef
用于获取真实dom和vue中ref一个道理 只不过变成了.current
import React, { useRef } from 'react';const MyComponent = () => {const inputRef = useRef(null);const focusInput = () => {if (inputRef.current) {inputRef.current.focus();}};return (<div><input ref={inputRef} type="text" /><button onClick={focusInput}>Focus Input</button></div>);};
常用hook
useState
语法: const [state, setState] = useState(initialState)
initialState 是初始状态,可以是任何类型(数字、字符串、对象等)。setState 是更新状态的函数。
这个不做举例了
useEffect
语法:useEffect(() => { … },[dependencies])
dependencies 是一个数组,包含 effect 依赖的值。当这些值发生变化时,effect 会重新执行。如果传入空数组 [],effect 只会在组件挂载和卸载时执行一次。
不做举例了
useContext
语法:const value = useContext(MyContext)
useContext 不接受第二个参数。它从最近的 <MyContext.Provider> 中获取当前上下文值
useReducer
用法: const [state, dispatch] = useReducer(reducer, initialState);
第二个参数: initialState 是 reducer 的初始状态,通常是一个对象或基本数据类型。
import React, { useReducer } from 'react';const initialState = { count: 0 };function reducer(state, action) {switch (action.type) {case 'increment':return { count: state.count + 1 };case 'decrement':return { count: state.count - 1 };default:throw new Error();}}const Counter = () => {const [state, dispatch] = useReducer(reducer, initialState);return (<div>Count: {state.count}<button onClick={() => dispatch({ type: 'increment' })}>+</button><button onClick={() => dispatch({ type: 'decrement' })}>-</button></div>);};
useMemo
用法:const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
dependencies 是一个数组,当数组中的任意一个值改变时,computeExpensiveValue 才会重新计算并返回新值
可以提高性能 记忆函数 也就是保存结果,组件多次渲染直接取缓存结果就行
import React, { useMemo } from 'react';const ExpensiveCalculation = ({ num }) => {const result = useMemo(() => {// 进行复杂计算return num * 2; // 示例计算}, [num]); // 依赖于 numreturn <div>Result: {result}</div>;};
useCallback
用法: const memoizedCallback = useCallback(() => { }, [dependencies]);
第二个参数: dependencies 是一个数组,当数组中的任意一个值改变时,返回新的回调函数。
更上面一样 就是保存函数
import React, { useState, useCallback } from 'react';const Button = React.memo(({ onClick }) => {console.log('Button Rendered');return <button onClick={onClick}>Click Me</button>;});const App = () => {const [count, setCount] = useState(0);const handleClick = useCallback(() => {setCount(count + 1);}, [count]); // 依赖于 countreturn (<div><Button onClick={handleClick} /><p>Count: {count}</p></div>);};
高阶组件
高阶组件(Higher-Order Component,简称 HOC)是 React 中一种用于复用组件逻辑的模式。它本质上是一个函数,接受一个组件作为参数,并返回一个新的组件。高阶组件可以用于许多场景,例如:状态管理、数据获取、权限控制等。
import React from 'react';// 原始组件const MyComponent = ({ extraInfo }) => (<div><p>这是我的组件。</p><p>{extraInfo}</p></div>);// 高阶组件const withExtraInfo = (WrappedComponent) => {return (props) => {const extraInfo = "附加信息:这是来自高阶组件的内容!";return <WrappedComponent {...props} extraInfo={extraInfo} />;};};// 使用高阶组件const EnhancedComponent = withExtraInfo(MyComponent);const App = () => (<div><EnhancedComponent /></div>);export default App;
什么时候使用
组件是既包含了ui界面的复用,也包含了逻辑的复用,高阶组件只是复用操作逻辑,运算,类似于vue中mixin的用途,当我们发现某个操作逻辑,或者某个运算经常出现的时候,我们可以提取为高阶组件
react性能问题和优化
Vue的因为是在get和set里触发更新
Vue在get部分有一个重要的操作-依赖收集
这样我们在更改了数据后,只会更新用到了这个数据的地方做到最小的更新范围
React的更新是调用方法时触发的,并没有依赖收集的过程所以他会更新整个组件树也就是会把子组件一起更新即使更新的数据和子组件没有任何关系
所以React最大的一个性能问题就是-React的某个组件的更新会连带着,他的子组件一起更新。所以我们需要解决这个问题让子组件只做合理的更新
React的时间切片
Vue有依赖收集,做到了最小的更新范围,而React没有做这个事情。所以React要更新,就会有很大的diff算法比对和计算工作
这大的更新量,虚拟dom比对和计算会花很大时间,这样可能会阻塞住浏览器的工作,导致页面长时间白屏
React为了解决这个问题选择另一种策略-时间切片,也就是先计算一部分更新,然后让渡给渲染进程 然后再进行下一步更新我从使用者的角度 就不会出现长时间白屏了。
fiber
为了支持这种切片,我们需要把更新化成一个个单元,然后我们也必须有回复上一次计算进度的能力
所以react设计一种数据结构-fiber
每一个组件会被转化为一个fiber结构的对象,组成一个个单元。Fiber让我们有了回复上次中断的计算进度的能力
类似于vue中的虚拟节点vnode, Both Fiber 和 vnode 都是对真实 DOM 的抽象,旨在提高性能和效率。它们允许框架在内存中处理组件树,而不是直接操作 DOM。
避免父组件数据导致子组件更新
React.memo子组件 让它缓存
我们特别注意父组件传入的方法,对象,数组这样的引用类型
用useCallback包裹传递给子组件的方法
state对象,数组数据,要用useMemo包裹起来
import React, { useState, useCallback, useMemo } from 'react';// 子组件const ChildComponent = React.memo(({ handleClick, data }) => {console.log('ChildComponent rendered');return (<div><button onClick={handleClick}>Click Me</button><ul>{data.map((item, index) => (<li key={index}>{item}</li>))}</ul></div>);});// 父组件const ParentComponent = () => {const [count, setCount] = useState(0);const [items, setItems] = useState(['Item 1', 'Item 2']);// 使用 useCallback 包裹传递给子组件的方法const handleClick = useCallback(() => {setCount(count + 1);}, [count]);// 使用 useMemo 包裹传递给子组件的数组数据const memoizedItems = useMemo(() => {return items;}, [items]);return (<div><h1>Count: {count}</h1><ChildComponent handleClick={handleClick} data={memoizedItems} /></div>);};export default ParentComponent;
如果对你有所帮助的话就点个关注吧,会持续更新技术文章
相关文章:
根据Vue对比来深入学习React 下 props 组件传值 插槽 样式操作 hooks 高阶组件 性能优化
文章目录 函数组件的特点props组件间的传值父传子看上例子传父兄弟组件传值祖先组件传值 插槽基础插槽具名插槽作用域插槽 样式操作**CSS Modules** 生命周期useRef常用hookuseStateuseEffectuseContextuseReduceruseMemouseCallback 高阶组件什么时候使用 react性能问题和优化…...
HTML(六)超链接
HTML讲解(一)body部分_html body-CSDN博客 <!DOCTYPE html> <html><head><meta charset"UTF-8" /><title>title</title> </head><body><a href"https://blog.csdn.net/2301_8034953…...
【Coroutines】Implement Lua Coroutine by Kotlin - 2
Last Chapter Link 文章目录 Symmetric CoroutinesNon-Symmetric Coroutine SampleSymmetric Coroutine SampleHow to Implement Symmetric CoroutinesWonderful TricksCode DesignTail Recursion OptimizationFull Sources Symmetric Coroutines in last blog, we have talk…...
java计算机毕设课设—扫雷游戏(附源码、文章、相关截图、部署视频)
这是什么系统? 资源获取方式再最下方(本次10月份活动福利,免费提供下载,自行到对应的方式1下载,csdn的0积分下载) java计算机毕设课设—扫雷游戏(附源码、文章、相关截图、部署视频) 基于Java的扫雷游戏…...
AndroidLogger 使用问题
Q1:解压zip后,启动Notepad未看到AndroidLogger工具栏 请检查plugins下安装位置是否正确,必须与下图一致,再确认Notepad 是否为 x64 ? Q2:使用 adb 可以显示已连接,但是获取不到日志 暂时不确定问…...
数据库常见面试
8道面试题 目录 目录 7道面试题 1.怎样进行sql优化 4、group by优化 5、limit优化 6、count优化 7、update优化 2.。怎样查看sql执行情况呢(哪个关键字),说说你对这个关键字的认识 4) possible_key: 5) key 3.说说你对innodb和 myisam的理解 …...
boxplot 绘制箱线图,添加数据点
先看效果图 import matplotlib.pyplot as plt #! 解决不显示的问题:中文设置为宋体格式 plt.rcParams[font.family] ["Times New Roman", SimSun]def plot_boxplot(data_list, out_file, x_custom_labels):# 画图fig, ax plt.subplots(figsize(90, 6…...
用sdkman管理多个jdk切换
前言 最近项目前后端进行升级,需要在jdk8和jdk17两个版本切换。最简单的是通过手动切换,但切换过程太繁琐,修改环境变量,达到切换目的。于是尝试其它解决方案,最终确实使用sdkman工具。 sdkman 是一款面向Java开发者的…...
【AIGC】ChatGPT提示词Prompt高效编写模式:结构化Prompt、提示词生成器与单样本/少样本提示
💯前言 在如今AI技术迅猛发展的背景下,尽管像ChatGPT这样的大型语言模型具备强大的生成能力,但它们的输出质量有时仍难以完全满足我们的预期。为了让ChatGPT生成更加准确、可靠的内容,掌握高效的Prompt编写技巧变得尤为重要。本文…...
反调式实战(有道翻译窗口弹出)
1.添加脚本断点实现源码获取 2.Function构造器构造debugger 因为是窗口被弹出的情况,所以window.closefunction()构造debugger。 3.定位到影响弹出的JavaScript代码片段 反调试思想:置空和替换,所以将其JavaScript进行注释或者删除。 这里主…...
verilog端口使用注意事项
下图存在组合逻辑反馈环,即组合逻辑的输出反馈到输入(赋值的左右2边存在相同的信号),此种情况会造成系统不稳定。比如在data_in20的情况下,在data_out0 时候,输出的数据会反馈到输入,输入再输出,从而造成不…...
Docker常用命令大全汇总
Docker是一种流行的容器化平台,可以在一个独立的、隔离的环境中构建、部署和运行应用程序。了解Docker常用命令可以帮助我们更高效地管理容器,快速开发和部署应用。本文将整理一系列Docker的常用命令,便于日常使用和学习。 1 Docker基础命令 1.1 启动/停止/重启docker # …...
LVS-DR+Keepalived 高可用群集部署
LVS-DRKeepalived 高可用群集部署 Keepalived 的工作原理LVSKeepalived 高可用群集部署配置负载调度器(主、备相同)关闭防火墙和核心防护及准备IPVS模块配置keeplived(主、备DR 服务器上都要设置)启动 ipvsadm 服务调整 proc 响应…...
【elasticsearch】安装和启动
启动 Elasticsearch 并验证其是否成功运行通常涉及以下步骤: 下载和安装 Elasticsearch: 访问 Elasticsearch 官方网站下载页面:https://www.elastic.co/guide/en/elasticsearch/reference/current/install-elasticsearch.html根据你的操作系…...
Golang 逃逸分析(Escape Analysis)理解与实践篇
Golang 逃逸分析(Escape Analysis)理解与实践篇 文章目录 1.逃逸分析2.相关知识(栈、堆、GC分析)3.逃逸分析综合-实践 demo 逃逸分析(Escape Analysis)是编译器在编译期进行的一项优化技术,是Gl…...
React入门 9:React Router
1. 什么是路由 路由(routing)就是通过互联的网络把信息从源地址传输到目的地址的活动。 以上是中文维基百科对路由的解释。通俗的来讲,把一个地方的信息传输到他想去的目的地的过程,就叫路由。 2. 用代码解释路由 需求:…...
MATLAB基础应用精讲-【数模应用】Bland-Altman图(附python和R语言代码实现)
目录 前言 几个高频面试题目 Bland-altman图:如何改变y轴 算法原理 Bland-Altman一致性分析 一致性界限 1. 背景介绍 2. Bland-Altman 法 3. batplot 命令介绍 4. 应用实例 Prism GraphPad实现Bland-Altman图 1.输入数据 2.从数据表中选择Bland-Altman分析 3.检…...
ARM/Linux嵌入式面经(四一):中兴面经
1. 请介绍一下您在嵌入式系统开发中的项目经验。 在嵌入式系统开发领域,我积累了丰富的项目经验,这些经验不仅锻炼了我的技术能力,也让我对嵌入式系统的设计和实现有了更深入的理解。以下是我参与的一个具有代表性的嵌入式系统开发项目的详细介绍: 项目背景 该项目是为一…...
鸿蒙虚拟运行环境
加一个环境变量:%SystemRoot%\System32\Wbem pushd "%~dp0" dir /b %SystemRoot%\servicing\Packages\*Hyper-V*.mum >hyper-v.txt for /f %%i in (findstr /i . hyper-v.txt 2^>nul) do dism /online /norestart /add-package:"%SystemRoot%…...
SpringCloud-Consul
为什么引入 Consul 简介以及安装 控制台 localhost:8500 服务注册与发现 服务端 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-consul-discovery</artifactId><exclusions><exclusio…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
Python Einops库:深度学习中的张量操作革命
Einops(爱因斯坦操作库)就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库,用类似自然语言的表达式替代了晦涩的API调用,彻底改变了深度学习工程…...
macOS 终端智能代理检测
🧠 终端智能代理检测:自动判断是否需要设置代理访问 GitHub 在开发中,使用 GitHub 是非常常见的需求。但有时候我们会发现某些命令失败、插件无法更新,例如: fatal: unable to access https://github.com/ohmyzsh/oh…...
Linux安全加固:从攻防视角构建系统免疫
Linux安全加固:从攻防视角构建系统免疫 构建坚不可摧的数字堡垒 引言:攻防对抗的新纪元 在日益复杂的网络威胁环境中,Linux系统安全已从被动防御转向主动免疫。2023年全球网络安全报告显示,高级持续性威胁(APT)攻击同比增长65%,平均入侵停留时间缩短至48小时。本章将从…...
Xcode 16 集成 cocoapods 报错
基于 Xcode 16 新建工程项目,集成 cocoapods 执行 pod init 报错 ### Error RuntimeError - PBXGroup attempted to initialize an object with unknown ISA PBXFileSystemSynchronizedRootGroup from attributes: {"isa">"PBXFileSystemSynchro…...
