千峰React:函数组件使用(2)

前面写了三千字没保存,恨!

批量渲染

function App() {const list = [{id:0,text:'aaaa'},{id:1,text:'bbbb'},{id:2,text:'cccc'}]//   for (let i = 0; i < list.length; i++) {//     list[i] = <li>{list[i]}</li>//   }return (<div><ul>{list.map((item) => <li key={item.id}>{item.text}</li>)}</ul></div>)
}
export default App

点标记写法

// function Welcome() {
//   return <div>hello Welcome</div>
// }// function App() {
//   return (
//     <div>
//       <Welcome />
//       <Welcome></Welcome>
//     </div>
//   )
// }
// export default Appconst Qf = () => {return <div>hello Qf</div>
}Qf.Welcome = () => {return <div>hello Welcome</div>
}function App() {return (<div><Qf.Welcome /><Qf.Welcome></Qf.Welcome></div>)
}
export default App

组件通信

import PropTypes from 'prop-types'
//子组件
function Welcome({ count, msg,isShow }) {return (<div>hello Welcome,{count},{msg},{isShow+''}</div>)
}// 添加 prop-types 验证
Welcome.propTypes = {count: PropTypes.string.isRequired, // 验证 count 是字符串并且是必传的msg: PropTypes.string.isRequired, // 验证 msg 是字符串并且是必传的isShow: PropTypes.string.isRequired, // 验证isShow是字符串并且是必传的
}//父组件
function App() {const count='我是个变量'return (<div><Welcome count={count} msg='hi react' isShow /></div>)
}
export default App

组件组合

import PropTypes from 'prop-types'
//子组件
function Welcome() {return <div>hello Welcome</div>
}function Head() {return <div>hello Head</div>
}// 添加 prop-types 验证
Welcome.propTypes = {count: PropTypes.string.isRequired, // 验证 count 是字符串并且是必传的msg: PropTypes.string.isRequired, // 验证 msg 是字符串并且是必传的isShow: PropTypes.string.isRequired, // 验证isShow是字符串并且是必传的
}//父组件
function App() {return (<div>hello App<Welcome><Head /></Welcome></div>)
}
export default App

可以看见这个Head被包在Welcome里 是渲染不出来的

使用props的children属性传递子组件

import PropTypes from 'prop-types'function Head() {return <div>hello Head</div>
}function Welcome({ children }) {return (<div>hello Welcome{children}</div>)
}// 添加 prop-types 验证
Welcome.propTypes = {count: PropTypes.string.isRequired, // 验证 count 是字符串并且是必传的children: PropTypes.string.isRequired, 
}//父组件
function App() {return (<div>hello App<Welcome><Head /></Welcome></div>)
}
export default App

另一种写法

import PropTypes from 'prop-types'function Head({ count }) {return <div>hello Head,{count}</div>
}function Welcome() {const count = 456return (<div>hello Welcome<Head count={count} /></div>)
}
// 为 Head 组件添加 prop-types 验证
Head.propTypes = {count: PropTypes.number.isRequired, // 验证 count 是数字并且是必传的
}// 添加 prop-types 验证
Welcome.propTypes = {
}//父组件
function App() {return (<div>hello App<Welcome><Head /></Welcome></div>)
}
export default App

import PropTypes from 'prop-types'// 为 Head 组件添加 prop-types 验证
Head.propTypes = {count: PropTypes.number.isRequired, // 验证 count 是数字并且是必传的
}// 添加 prop-types 验证
Welcome.propTypes = {count: PropTypes.number.isRequired, // 验证 Welcome 组件的 count 是必传的
}function Head({ count }) {//接收countreturn <div>hello Head,{count}</div>
}function Welcome() {const count = 456return (<div>hello Welcome<Head count={count} />{/* {挂载count} */}</div>)
}//父组件
function App() {const count = 123return (<div>hello App<Welcome count={count} /></div>)
}
export default App

如何分别传递多组内容

所有的内容放到children里,没办法独立使用

import PropTypes from 'prop-types'function Welcome({ children }) {return (<div>{children}hello Welcome{children}</div>)
}// 添加 prop-types 验证
Welcome.propTypes = {count: PropTypes.string.isRequired, // 验证 count 是字符串并且是必传的children: PropTypes.string.isRequired,
}//父组件
function App() {return (<div>hello App<Welcome><div>aaaaaaaaaaaa</div><div>bbbbbbbbbbbb</div></Welcome></div>)
}
export default App

使用多组内容传递

import PropTypes from 'prop-types'function Welcome({ bottom, top }) {return (<div>{top}hello Welcome{bottom}</div>)
}// 添加 prop-types 验证
Welcome.propTypes = {count: PropTypes.string.isRequired, // 验证 count 是字符串并且是必传的children: PropTypes.string.isRequired,top: PropTypes.string.isRequired,bottom: PropTypes.string.isRequired,
}//父组件
function App() {return (<div>hello App<Welcometop={<div>aaaaaaaaaaaa</div>}bottom={<div>bbbbbbbbbbbb</div>}></Welcome></div>)
}
export default App

通信的数据如何添加默认值

import PropTypes from 'prop-types'function Welcome({ count, msg }) {return (<div>hello Welcome,{count},{msg}</div>)
}// 添加 prop-types 验证
Welcome.propTypes = {count: PropTypes.string.isRequired, // 验证 count 是字符串并且是必传的children: PropTypes.string.isRequired,msg: PropTypes.string.isRequired,
}//父组件
function App() {return (<div>hello App{/* { 传递参数的情况} */}<Welcome count={123} msg='hello react' />{/* { 不传递参数的情况} */}<Welcome /></div>)
}
export default App

如果有接收参数的位置,但是不传递参数,就会这样👇

为了解决这个问题,就提供了默认参数

ES6是这么做的:

import PropTypes from 'prop-types'// function Head() {
//   return <div>hello Head</div>
// }function Welcome({ count='我是count的默认值', msg='我是msg的默认值'}) {return (<div>hello Welcome,{count},{msg}</div>)
}// 添加 prop-types 验证
Welcome.propTypes = {count: PropTypes.string.isRequired, // 验证 count 是字符串并且是必传的children: PropTypes.string.isRequired,msg: PropTypes.string.isRequired,
}//父组件
function App() {return (<div>hello App{/* { 传递参数的情况} */}<Welcome count={123} msg='hello react' />{/* { 不传递参数的情况} */}<Welcome /></div>)
}
export default App

也可以使用React原生的:

import PropTypes from 'prop-types'function Welcome({ count,msg}) {return (<div>hello Welcome,{count},{msg}</div>)
}// 添加 prop-types 验证
Welcome.propTypes = {count: PropTypes.number, // 验证 count 是数字(非必传)msg: PropTypes.string, // 验证 msg 是字符串(非必传)
}Welcome.defaultProps = {count: 0,msg:'我是默认值'
}
//父组件
function App() {return (<div>hello App{/* { 传递参数的情况} */}<Welcome count={123} msg='hello react' />{/* { 不传递参数的情况} */}<Welcome /></div>)
}
export default App

但是我失败了

为什么?因为:

我是19,别管了就用es6吧

通信数据如何限定类型

一般更推荐ts,但是ts不一定是项目用的

类型验证就用我之前已经写过的这部分👇

// 添加 prop-types 验证
Welcome.propTypes = {count: PropTypes.number, // 验证 count 是数字(非必传)msg: PropTypes.string, // 验证 msg 是字符串(非必传)
}

浏览器莫名其妙不报错,可能还是react的版本问题

如果希望有个数据传过来,数字和字符串都是符合要求的类型,也就是筛出两种类型可以这么写:

// 添加 prop-types 验证
Welcome.propTypes = {count:PropTypes.oneOfType([PropTypes.string,PropTypes.number,]),// 验证 count 是数字或字符串(非必传)msg: PropTypes.string, // 验证 msg 是字符串(非必传)
}

还可以有一些更复杂的限定,比如限定值是多少:

import PropTypes from 'prop-types'function Welcome({ count, msg }) {return (<div>hello Welcome,{count},{msg}</div>)
}// 添加 prop-types 验证
Welcome.propTypes = {count: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), // 验证 count 是数字或字符串(非必传)msg: PropTypes.string, // 验证 msg 是字符串(非必传)type: PropTypes.oneOf(['primary', 'success', 'error']),
}Welcome.defaultProps = {count: 0,msg: '我是默认值',
}
//父组件
function App() {return (<div>hello App{/* { 正确的情况} */}<Welcome count={123} msg='hello react' type='我是错的' /></div>)
}
export default App

这里按理来说应该会报错,但是并没有!!!

传值其实也可以传jsx:

import PropTypes from 'prop-types'function Welcome({ count, msg }) {return (<div>hello Welcome,{count},{msg}</div>)
}// 添加 prop-types 验证
Welcome.propTypes = {count: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), // 验证 count 是数字或字符串(非必传)msg: PropTypes.string, // 验证 msg 是字符串(非必传)type: PropTypes.oneOf(['primary', 'success', 'error']),icon: PropTypes.element//针对jsx的类型,element
}Welcome.defaultProps = {count: 0,msg: '我是默认值',
}
//父组件
function App() {return (<div>hello App{/* { 正确的情况} */}<Welcomecount={123}msg='hello react'type='primary'icon={<div className='icon-close'></div>}/></div>)
}
export default App

组件必须是个纯函数

react的严格模式会检测我们当前的组件是不是纯函数

纯函数组件是指:

  • 组件的输出(渲染结果)完全由输入(props 和 state)决定。

  • 组件没有副作用(例如直接修改 DOM、发起网络请求、使用 setTimeout 等)。

  • 组件在相同的 props 和 state 下,总是返回相同的渲染结果

两次结果一样

在严格模式下,React 会 故意调用两次 函数组件(包括其渲染逻辑),如果组件是纯函数,两次调用的结果应该完全相同。

比如++操作,如果把对count的声明写函数外面,那么就不是一个纯函数:

预期来说count=2,最后等于3是因为React故意调用两次函数组件,两次的结果一次为2,一次为3,所以不是纯函数组件

这样就是了

function App() {let count = 1count++console.log(count)return <div>{count}</div>
}
export default App

两次结果相同

当然,不开严格模式的话就没有这种情况啦,一般建议开启

相同的输入和输出

意思就是给函数传入相同的参数,就应该传出相同的输出

这是一个纯函数,传入2都是4

这不是纯函数,传入2得到的输出不一定相同

纯函数可以保证我们的组件更健壮

组件的状态和useState

 useState基础使用

useState 是一个 React Hook(函数),它允许我们向组件添加一个状态变量(State), 从而控制影响组件的渲染结果

状态变量是 React 组件内部的一个特殊变量,用于存储组件的数据,当状态变量的值发生变化时,React 会自动重新渲染组件,以反映最新的数据

状态变量和普通JS变量不同的是,状态变量一旦发生变化组件的视图UI也会跟着变化(数据驱动视图)

useState是React里的方法,返回的是个数组,数组里有两项:[状态变量,修改状态变量的方法]

只有用这个专门的修改状态变量的方法修改变量,才会在ui渲染里起效

//useState实现一个计数器按钮
import { useState } from 'react'
function App() {// const handleClick = (name,e) => console.log('button被点击了name:',name,'e:',e)//1、调用useState添加一个状态变量const [count, setCount] = useState(0)//2、点击事件回调const handleClick = () => { setCount(count+1) }return (<div className="App"><button onClick={handleClick}>{count}</button></div>);
}
export default App;

count++ 会直接修改 count 的值,而 React 的状态变量是不可变的(Immutable),不能直接修改。

那我就要问了:const handleClick = () => { setCount(count++) }这么写不也是通过setState 函数更新状态吗?为什么不行?

count++ 会先返回当前的值,再进行自增操作,而 React 的 setState 需要传入新的值,而不是修改原值。

那++count呢?++count 会先对 count 进行自增操作,然后返回自增后的值。这个操作会直接修改当前 count 的值,而 React 需要的是通过 setCount 来触发状态的更新,这就相当于状态变量的修改是你自己改的,不是通过对应的方法改的

正确的写法是应该直接传入 count + 1,而不是 count++,因为 count++ 只是修改了本地变量

对于对象来说也是这样,应该把新的对象写进对应方法,而不是直接修改

import { useState } from 'react'function App () {let [count, setCount] = useState(0)const handleClick = () => {// 直接修改 无法引发视图更新// count++// console.log(count)setCount(count + 1)}// 修改对象状态const [form, setForm] = useState({ name: 'jack' })const changeForm = () => {// 错误写法:直接修改// form.name = 'john'// 正确写法:setFrom 传入一个全新的对象setForm({...form,name: 'john'})}return (<div><button onClick={handleClick}>{count}</button><button onClick={changeForm}>修改form{form.name}</button></div>)
}export default App

状态如何改变视图

先看这段代码

function App() {let count = 0const increment = () => {count++ // 修改普通变量console.log(count) // 值会变化,但不会触发重新渲染}console.log(1234567)return (<div><p>{count}</p><button onClick={increment}>Increment</button></div>)
}
export default App

    点击按钮时,count 的值会增加,但页面不会重新渲染,因此用户看不到变化。

    状态变量会被记忆上一次的值,每次渲染函数返回的内容不一样,所以在察觉变化的时候React会重新调用渲染函数,并且改变count,所以每次结果都不一样)

    普通变量的变化不会通知 React,所以React 不会调用渲染函数,所以不会重新渲染jsx。

    顺便:Mujica第八集拍出来其实是为了缩短中国人寿命降低生产力,是日本人为了打败中国人投放的精神类武器,是日本成为东亚第一强国的邪恶计划最核心的一步

    本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/71706.shtml

    如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

    相关文章

    Hot100 动态规划

    动态规划 动规五部曲&#xff1a; 确定dp数组以及下标的含义确定递推公式dp数组如何初始化确定遍历顺序举例推导dp数组 70. 爬楼梯 - 力扣&#xff08;LeetCode&#xff09; 爬到第一层楼梯有一种方法&#xff0c;爬到二层楼梯有两种方法。 那么第一层楼梯再跨两步就到第三…

    Rust语言基础知识详解【一】

    1.在windows上安装Rust Windows 上安装 Rust 需要有 C 环境&#xff0c;以下为安装的两种方式&#xff1a; 1. x86_64-pc-windows-msvc&#xff08;官方推荐&#xff09; 先安装 Microsoft C Build Tools&#xff0c;勾选安装 C 环境即可。安装时可自行修改缓存路径与安装路…

    文章精读篇——OMG-Seg

    题目&#xff1a;OMG-Seg : Is One Model Good Enough For All Segmentation? 作者&#xff1a;Xiangtai Li1 † Haobo Yuan1 Wei Li1 Henghui Ding1 Size Wu1 Wenwei Zhang1Yining Li2 Kai Chen2 Chen Change Loy1 代码&#xff1a;OMG-Seg 会议&#xff1a;cvpr2024 边读…

    vite 开启 gzip压缩

    使用vite 如何开启 gzip压缩 文章目录 使用vite 如何开启 gzip压缩1. 引言为什么需要 Gzip 压缩&#xff1f;Gzip 压缩的作用 2. Vite 项目中的 Gzip 压缩Vite 的基本概念Gzip 压缩的原理 3. 使用 Vite 插件开启 Gzip 压缩安装 vite-plugin-compression配置 vite-plugin-compre…

    【Qt学习】| 如何使用QVariant存储自定义类型

    QVariant是Qt框架中的一个通用数据类型&#xff0c;可以存储多种类型的数据&#xff0c;主要作用是提供一种类型安全的方式来存储和传递不同类型的数据&#xff0c;而不需要显示地指定数据类型。 QVariant提供了诸多构造函数可以非常方便地对基础数据类型&#xff08;如&#x…

    【Python量化金融实战】-第1章:Python量化金融概述:1.4 开发环境搭建:Jupyter Notebook、VS Code、PyCharm

    在量化金融开发中&#xff0c;选择合适的开发环境至关重要。本章介绍三种主流工具&#xff1a;Jupyter Notebook&#xff08;交互式分析&#xff09;、VS Code&#xff08;轻量级编辑器&#xff09;、PyCharm&#xff08;专业IDE&#xff09;&#xff0c;并通过实战案例展示其应…

    查看 nginx 是否已经启动

    在 Ubuntu 或其他 Linux 系统上&#xff0c;要查看 Nginx 是否已经启动&#xff0c;您可以使用以下几种方法之一&#xff1a; 方法一&#xff1a;使用 systemctl 命令 Nginx 通常作为 systemd 服务运行&#xff0c;因此您可以使用 systemctl 命令来检查其状态。 打开终端。 …

    解释 Vue 中的虚拟 DOM,如何通过 Diff 算法最小化真实 DOM 更新次数?

    1. 虚拟DOM核心原理&#xff08;附代码示例&#xff09; // 简化的VNode结构示意 class VNode {constructor(tag, data, children) {this.tag tag // 标签名this.data data // 属性/指令等this.children children // 子节点数组} }// 两个新旧虚拟节点树示例 const oldV…

    Pytorch使用手册-音频数据增强(专题二十)

    音频数据增强 torchaudio 提供了多种方式来增强音频数据。 在本教程中,我们将介绍一种应用效果、滤波器、RIR(房间脉冲响应)和编解码器的方法。 最后,我们将从干净的语音合成带噪声的电话语音。 import torch import torchaudio import torchaudio.functional as Fprin…

    Linux-Ansible模块扩展

    文章目录 Archive UnarchiveSetup模块Lineinfile Replace &#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;Linux专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2025年02月23日18点11分 Archive Unarchive Archive和Unarchive模块 需求&#x…

    Redhat及其衍生系统安装python

    目录 更新包列表 安装 Python 3 安装特定版本的 Python 验证安装 安装 pip 更新包列表 在安装任何软件之前&#xff0c;建议先更新系统的包列表&#xff0c;以确保安装的是最新版本的软件包&#xff1a; sudo dnf update 安装 Python 3 RHEL 9 默认安装了 Python 3&…

    Python条件控制和循环语句

    目录 条件控制语句 1. if 语句 2. if-else 语句 3. if-elif-else 语句 循环语句 1. for 循环 2. while 循环 循环控制语句 1. break 语句 2. continue 语句 3. else 子句&#xff08;与循环结合&#xff09; 嵌套循环 常见应用场景 条件控制 循环语句 条件控制语…

    *PyCharm 安装教程

    PyCharm 安装教程&#xff0c;适用于 Windows、macOS 和 Linux 系统&#xff1a; 1. 下载 PyCharm 官网地址&#xff1a;https://www.jetbrains.com/pycharm/版本选择&#xff1a; Community&#xff08;社区版&#xff09;&#xff1a;免费&#xff0c;适合基础 Python 开发…

    Three.js 快速入门教程【二】透视投影相机

    系列文章目录 系列文章目录 Three.js 快速入门教程【一】开启你的 3D Web 开发之旅 Three.js 快速入门教程【二】透视投影相机 Three.js 快速入门教程【三】渲染器 Three.js 快速入门教程【四】三维坐标系 Three.js 快速入门教程【五】动画渲染循环 Three.js 快速入门教程【六…

    IntelliJ IDEA 控制台输出中文出现乱码

    IntelliJ IDEA 控制台输出中文出现乱码通常是由于编码设置不一致导致的。以下是常见原因及解决方法 1. 项目编码设置 检查路径&#xff1a;File → Settings → Editor → File Encodings 确保 Project Encoding、Global Encoding 和 Default Encoding for Properties Files 均…

    C#初级教程(7)——初级期末检测

    练习 1&#xff1a;计算圆的周长和面积 改编题目&#xff1a;编写一个 C# 程序&#xff0c;让用户输入圆的半径&#xff0c;然后计算并输出该圆的周长和面积&#xff0c;结果保留两位小数。 using System;class CircleCalculation {static void Main(){const double pi 3.14…

    Java 集合:单列集合和双列集合的深度剖析

    引言 在 Java 编程中&#xff0c;集合是一个非常重要的概念。它就像是一个容器&#xff0c;能够存储多个数据元素&#xff0c;帮助我们更方便地管理和操作数据。Java 集合框架主要分为单列集合和双列集合两大类&#xff0c;它们各自有着独特的特点和适用场景。接下来&#xff0…

    layui 远程搜索下拉选择组件(多选)

    模板使用&#xff08;lay-module/searchSelect&#xff09;&#xff0c;依赖于 jquery、layui.dist 中的 dropdown 模块实现&#xff08;所以data 格式请参照 layui文档&#xff09; <link rel"stylesheet" href"layui-v2.5.6/dist/css/layui.css" /&g…

    通俗易懂的DOM1级标准介绍

    前言 在前端开发中&#xff0c;DOM&#xff08;文档对象模型&#xff09;是我们操作网页内容的核心工具。前面的文章我们介绍了DOM0级、DOM2级事件模型&#xff0c;没有DOM1级事件模型这种概念&#xff0c;但有DOM1级标准。今天我们就来讨论DOM1级标准&#xff0c;看看它到底做…

    python~http的请求参数中携带map

    背景 调试 http GET请求的 map 参数&#xff0c;链路携带参数一直有问题&#xff0c;最终采用如下方式携带map 解决 user{"demo":"true","info":"王者"}url encode之后的效果如下所示 user%7B%22demo%22:%22true%22,%22info%22:%22…