【React】React学习:从初级到高级(一)

React学习[一]

  • 1 UI描述
    • 1.1 组件的创建与使用
      • 1.1.1 创建组件
      • 1.1.2 使用组件
    • 1.2 组件的导入与导出
      • 1.2.1 根组件文件
      • 1.2.2 导出和导入一个组件
      • 1.2.3 从同一文件中导出和导入多个组件
    • 1.3 使用JSX书写标签语言
      • 1.3.1 JSX:将标签引入JavaScript
      • 1.3.2 将HTML转换为JSX
      • 1.3.3 高级提示:使用JSX转化器
    • 1.4 在JSX中通过大括号使用JavaScript
      • 1.4.1 使用引号传递字符串
      • 1.4.2 使用"双大括号":JSX中的CSS和对象
    • 1.5 将Props传递给组件
      • 1.5.1 将Props传递给组件
      • 1.5.2 给props指定一个默认值
      • 1.5.3 使用JSX展开语法传递props
      • 1.5.4 将JSX作为子组件传递
      • 1.5.5 props如何随时间变化
    • 1.6 条件渲染
      • 1.6.1 条件返回JSX
      • 1.6.2 选择性地返回null
      • 选择性地包含JSX
      • 选择性地将JSX赋值给变量
    • 1.7 渲染列表
      • 1.7.1 从数组中渲染数据
      • 1.7.2 对数组项进行过滤
      • 1.7.3 用key保持列表项的顺序
    • 1.8 保持组件为纯函数
      • 1.8.1 局部`mutation`

1 UI描述

1.1 组件的创建与使用

组件是用户界面UI的构成要素。创建一个组件可以分为三步:

1.1.1 创建组件

  1. 导出组件

    • export default
  2. 定义函数

    • function name(props) {}

    • 定义组件的时候,组件的名称必须以大写字母开头,否则将无法运行。

      HTML标签是小写的

  3. 添加标签

    • JSX(使用JavaScript)

    • TSX(使用TypeScript)

    • 注意:如果标签和return 不在同一行,则必须把它包裹在一堆括号中,

      没有括号包裹的话,任何在return 下一行的代码都将被忽略!

1.1.2 使用组件

在父组件中引入即可,但是不要在组件中定义组件。应该在顶层定义组件。当子组件需要使用父组件的数据时,需要 通过 props 的形式进行传递,而不是嵌套定义。

1.2 组件的导入与导出

1.2.1 根组件文件

相当于把所有模块化组件做一个集成的文件。


1.2.2 导出和导入一个组件

对组件进行拆分可以分为三步:

  1. 创建一个新的JS文件来存放该组件
  2. 导出该文件中的函数组件(可以使用默认导出或者具名导出
  3. 在需要使用该组件的文件中导入(可以根据相应的导出的方式使用默认导入或者具名导入
语法导出语句导入语句
默认export default function Hello() {}import Hello from './Hello.js';
具名export function Hello() {}import { Hello } from './Hello.js';

注意:在引入一些文件时虽然没有添加.js文件名后缀,比如./Hello.js还是./HelloReact里都能正常使用,只是前者更符合原生ES模块

一个文件里有且仅有一个默认导出,但是可以有任意多个具名导出。组件的导出方式决定了其导入方式。通常,文件中仅包含一个组件时,会选择默认导出,而当文件中包含多个组件或某个值需要导出时,则会选择具名导出。


1.2.3 从同一文件中导出和导入多个组件

同一文件中,有且仅有一个默认导出,但可以有多个具名导出!

1.3 使用JSX书写标签语言

JSX是JavaScript语法扩展,可以在JavaScript文件中写类似HTML的标签。(虚拟DOM)

1.3.1 JSX:将标签引入JavaScript

**在 React 中,渲染逻辑和标签共同存在于同一个地方——组件。**将一个按钮的渲染逻辑和标签放在一起可以确保它们在每次编辑时都能保持互相同步。每个 React 组件都是一个 JavaScript 函数,它会返回一些标签,React 会将这些标签渲染到浏览器上。

JSX React 是相互独立的东西。JSX 是一种语法扩展,而 React 则是一个 JavaScript 的库。


1.3.2 将HTML转换为JSX

JSX规则:

  1. 只能返回一个根元素

    • 如果想要在一个组件中包含多个元素,需要用一个父标签把它们包裹起来

    • 如果不想在标签中增加一个额外的 <div>,可以用 <></> 元素来代替:

      这个空标签被称作 Fragment. React Fragment 允许将子元素分组,而不会在 HTML 结构中添加额外节点。

    为什么多个 JSX 标签需要被一个父元素包裹?

    答:JSX 虽然看起来很像 HTML,但在底层其实被转化为了 JavaScript 对象,你不能在一个函数中返回多个对象,除非用一个数组把他们包装起来。这就是为什么多个 JSX 标签必须要用一个父元素或者 Fragment 来包裹。

  2. 标签必须闭合

  3. 使用驼峰式命名法给大部分属性命名

    • 由于历史原因,aria-*data-* 属性是以带 - 符号的 HTML 格式书写的。

1.3.3 高级提示:使用JSX转化器

将HTML转换为JSX:https://transform.tools/html-to-jsx


1.4 在JSX中通过大括号使用JavaScript

1.4.1 使用引号传递字符串

想把一个字符串属性传递给 JSX 时,把它放到单引号或双引号中

若想要动态指定可以使用{}

大括号内的任何JavaScript表达式都可以正常运行。

在 JSX 中,只能在以下两种场景中使用大括号:

  1. 用作 JSX 标签内的文本<h1>{name}'s To Do List</h1> 是有效的,但是 <{tag}>Gregorio Y. Zara's To Do List</{tag}> 无效。
  2. 用作紧跟在 = 符号后的 属性src={avatar} 会读取 avatar 变量,但是 src="{avatar}" 只会传一个字符串 {avatar}

1.4.2 使用"双大括号":JSX中的CSS和对象

对象也用大括号表示,例如 { name: "无敌是多么寂寞", inventions: 5 }。因此,为了能在 JSX 中传递,你必须用另一对额外的大括号包裹对象:person={{ name: "无敌是多么寂寞", inventions: 5 }}

import { getImageUrl } from './utils.js'const person = {name: 'Gregorio Y. Zara',imageId: '7vQD0fP',imageSize: 's',theme: {backgroundColor: 'black',color: 'pink'}
};export default function TodoList() {return (<div style={person.theme}><h1>{person.name}'s Todos</h1><imgclassName="avatar"src={getImageUrl(person)}alt={person.name}/><ul><li>Improve the videophone</li><li>Prepare aeronautics lectures</li><li>Work on the alcohol-fuelled engine</li></ul></div>);
}
// 将获取图片的语句封装成一个函数
export function getImageUrl(person) {return ('https://i.imgur.com/' +person.imageId +person.imageSize +'.jpg');
}

1.5 将Props传递给组件

React 组件使用 props 来互相通信。每个父组件都可以提供 props 给它的子组件,从而将一些信息传递给它。Props 可能会让你想起 HTML 属性,但你可以通过它们传递任何 JavaScript 值,包括对象、数组和函数

1.5.1 将Props传递给组件

父组件可以分两步将props传递给子组件

  1. 首先在父组件中将props传递给引用的子组件,使得子组件可以读取这些props

  2. 在子组件中读取props,这些 props 在 ({}) 之间,并由逗号分隔。比如

    function Avatar({ person, size }) {// 在这里 person 和 size 是可被子组件访问的
    }
    

props 正是 组件的唯一参数! React 组件函数接受一个参数,一个 props 对象。比如:

function Avatar(props) {let person = props.person;let size = props.size;// ...
}

1.5.2 给props指定一个默认值

如果想在没有指定值的情况下给 prop 一个默认值,可以通过在参数后面写 = 默认值来进行解构,比如:

function Avatar({ person, size = 100 }) {// ...
}

但是如果传递了 size={null}size={0},默认值将 被使用。

1.5.3 使用JSX展开语法传递props

先看两段代码感受一下

// 第一段
function Profile({ person, size, isSepia, thickBorder }) {return (<div className="card"><Avatarperson={person}size={size}isSepia={isSepia}thickBorder={thickBorder}/></div>);
}
// 第二段
function Profile(props) {return (<div className="card"><Avatar {...props} /></div>);
}

是不是觉得第二段用了展开语法的代码更简洁!但是这通常表示你应该拆分组件了,并需要将子组件作为JSX传递。

1.5.4 将JSX作为子组件传递

当将内容嵌套在 JSX 标签中时,父组件将在名为 children 的 prop 中接收到该内容。

function Card({ children }) {return (<div className="card">{children}</div>);
}export default function Profile() {return (<Card><h1>哎哟不错哦</h1></Card>);
}

可以将带有 children prop 的组件看作有一个“洞”,可以由其父组件使用任意 JSX 来“填充”。

1.5.5 props如何随时间变化

**一个组件可能会随着时间的推移收到不同的 props。**但是props的改变是父组件通过传递不同的props——新对象来改变的。旧props会被丢弃然后被JS引擎回收它们占用的内存.当需要交互性时,可以设置 state

1.6 条件渲染

1.6.1 条件返回JSX

可以用if else、&&、? :语句来写分支逻辑

1.6.2 选择性地返回null

例如:

function Item({ name, isPacked }) {if (isPacked) {return null;}return <li className="item">{name}</li>;
}export default function PackingList() {return (<section><h1>Sally Ride 的行李清单</h1><ul><Item isPacked={true} name="宇航服" /><Item isPacked={true} name="带金箔的头盔" /><Item isPacked={false} name="Tam 的照片" /></ul></section>);
}

实际上,在组件里返回 null 并不常见。通常情况下,可以在父组件里选择是否要渲染该组件。

选择性地包含JSX

可以使用三目运算符? :。如果代码有小段重复可以考虑用这个进行简单的条件判断。比如:

// 修改前
if (isPacked) {return <li className="item">{name}</li>;
}
return <li className="item">{name}</li>;// 修改后
return (<li className="item">{isPacked ? name + ' ✔' : name}</li>
);

或者用&&运算符

  return (<li className="item">{name} {isPacked && '✔'}</li>);

与表达式的判定若为false,React会将其视为控制,不会对其进行任何渲染。但切勿把数字放在&&左侧,因为如果左侧是0,React会渲染0

选择性地将JSX赋值给变量

结合if语句和let赋值变量可以更加灵活。因为可以使用 let 进行重复赋值,所以一开始可以将想展示的(这里指的是物品的名字)作为默认值赋予给该变量。

function Item({ name, isPacked }) {let itemContent = name;if (isPacked) {itemContent = name + " ✔";}return (<li className="item">{itemContent}</li>);
}export default function PackingList() {return (<section><h1>Sally Ride 的行李清单</h1><ul><Item isPacked={true} name="宇航服" /><Item isPacked={true} name="带金箔的头盔" /><Item isPacked={false} name="Tam 的照片" /></ul></section>);
}

1.7 渲染列表

操作数组中的数据,将一个数据集渲染成多个相似的组件。

1.7.1 从数组中渲染数据

利用map()函数

const people = ['凯瑟琳·约翰逊: 数学家','马里奥·莫利纳: 化学家','穆罕默德·阿卜杜勒·萨拉姆: 物理学家','珀西·莱温·朱利亚: 化学家','苏布拉马尼扬·钱德拉塞卡: 天体物理学家',
];export default function List() {const listItems = people.map(person =><li>{person}</li>);return <ul>{listItems}</ul>;
}

注意:这里还未给每个数据加上唯一标识符key

1.7.2 对数组项进行过滤

先利用filter()函数进行筛选,再利用map()函数进行渲染

import { people } from './data.js';
import { getImageUrl } from './utils.js';export default function List() {const chemists = people.filter(person =>person.profession === '化学家');const listItems = chemists.map(person =><li><imgsrc={getImageUrl(person)}alt={person.name}/><p><b>{person.name}:</b>{' ' + person.profession + ' '}{person.accomplishment}而闻名世界</p></li>);return <ul>{listItems}</ul>;
}

注意:这里还未给每个数据加上唯一标识符key.

箭头函数会隐式地返回位于 => 之后的表达式,所以可以省略 return 语句。不过,如果 => 后面跟了一对花括号 { ,那必须使用 return 来指定返回值! 箭头函数 => { 后面的部分被称为 “块函数体”,块函数体支持多行代码的写法,但要用 return 语句才能指定返回值。


1.7.3 用key保持列表项的顺序

必须给数组中的每一项都指定一个 key——它可以是字符串或数字的形式,只要能唯一标识出各个数组项就行。

直接放在 map() 方法里的 JSX 元素一般都需要指定 key 值!

一个合适的 key 可以帮助 React 推断发生了什么,从而得以正确地更新 DOM 树。

如果想让每个列表项都输出多个 DOM 节点而非一个的话,只能要么把生成的节点用一个 <div> 标签包裹起来,要么使用长一点但更明确的 <Fragment> 写法:

import { Fragment } from 'react';// ...const listItems = people.map(person =><Fragment key={person.id}><h1>{person.name}</h1><p>{person.bio}</p></Fragment>
);

这里的 Fragment 标签本身并不会出现在 DOM 上,这串代码最终会转换成 <h1><p><h1><p>…… 的列表。

key值的设定:

  • 来自数据库的数据:可以直接使用数据表中的主键
  • 本地产生数据:可以使用一个自增计数器或者一个类似 uuid 的库来生成 key。

key需要满足的条件

  • key 值在兄弟节点之间必须是唯一的。 不过不要求全局唯一,在不同的数组中可以使用相同的 key。
  • key 值不能改变。不要在运行过程中动态地产生 key。

React之所以需要key值,是因为即使元素的位置在渲染的过程中发生了改变,它提供的 key 值也能让 React 在整个生命周期中一直认得它。

注意,组件不会把 key 当作 props 的一部分。Key 的存在只对 React 本身起到提示作用。如果你的组件需要一个 ID,那么请把它作为一个单独的 prop 传给组件: <Profile key={id} userId={id} />

挑战题:

请根据给你的数组生成菜谱列表!其中每个菜谱,都用 <h2> 来显示它的名称,并在 <ul> 里列出它所需的原料。

data.js

export const recipes = [{id: 'greek-salad',name: '希腊沙拉',ingredients: ['西红柿', '黄瓜', '洋葱', '油橄榄', '羊奶酪'],},{id: 'hawaiian-pizza',name: '夏威夷披萨',ingredients: ['披萨饼皮', '披萨酱', '马苏里拉奶酪', '火腿', '菠萝'],},{id: 'hummus',name: '鹰嘴豆泥',ingredients: ['鹰嘴豆', '橄榄油', '蒜瓣', '柠檬', '芝麻酱'],},
];

App.js

import { recipes } from './data.js';function RecipeShow({ recipesList }) {return (<div>{recipesList.map(recipe =><div key={recipe.id}><h2>{recipe.name}</h2><ul>{recipe.ingredients.map(ingredent => <li key={ingredent}>{ingredent}</li>)}  </ul></div>)}</div>)
}function Card({children}) {return (<div>{ children }</div>)
}export default function RecipeList() {return (<Card><div><h1>菜谱</h1><RecipeShow recipesList={recipes} /></div></Card>);
}

1.8 保持组件为纯函数

一个React组件,不管什么时候给了它一个相同的输入,那么它的输出就是相同的,就像数学公式一样。比如y=2x,无论何时传x=3,其输出总是y=6

React 无法保证组件函数以任何特定的顺序执行,因此无法通过设置变量在它们之间进行通信。所有的交流都必须通过 props 进行。

1.8.1 局部mutation

我们将组件改变了预先存在的变量的值的现象称为突变(mutation)。局部突变的意思就是在渲染时更改刚刚创建的变量和对象,属于内部突变,不会影响函数外部的变量或函数。

但是事件处理程序无需是纯函数,包括更新屏幕、启动动画、更改数据等。

React为何侧重于纯函数?

  1. 复用性,适应不同环境
  2. 可以缓存纯函数的输出来跳过渲染,提高性能
  3. 在渲染深层组件树的过程中,如果数据发生了变化,可以随时安全停止计算,节省时间。

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

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

相关文章

Python进阶(1)

Python进阶&#xff08;1&#xff09; 文章目录 Python进阶&#xff08;1&#xff09;一&#xff1a;发送请求&#xff08;GET/POST&#xff09;1.1、方式一&#xff1a;http.client&#xff0c;以https方式为例1.1.1、GET1.1.2、POST 1.2、方式二&#xff1a;requests&#xf…

音视频 ffplay命令播放媒体

播放本地文件 ffplay -window_title "test time" -ss 2 -t 10 -autoexit test.mp4 ffplay buweishui.mp3播放网络流 ffplay -window_title "rtmp stream" rtmp://202.69.69.180:443/webcast/bshdlive-pc强制解码器 mpeg4解码器&#xff1a;ffplay -vco…

Mac安装Dart时,Homebrew报错 Error: Failure while executing

前言&#xff1a; 最近准备开发Flutter项目时&#xff0c;在安装环境时&#xff0c;安装Homebew时遇到了以下报错信息&#xff0c;在这里分享一下。 报错信息&#xff1a; ~ % brew tap dart-lang/dart > Tapping dart-lang/dart Cloning into /opt/homebrew/Library/Tap…

Java-集合框架-List,Set,Map,队列

文章目录 Java集合框架&#xff1a;List&#xff0c;Set&#xff0c;Map&#xff0c;队列Java集合框架是什么&#xff1f;如何使用&#xff1f;ListSetMap队列 什么场景使用&#xff1f;优缺点是什么&#xff1f;ListSetMap队列 Java示例List示例Set示例Map示例队列示例 对比 J…

BMC相关知识

简介 BMC&#xff08;Baseboard Management Controller&#xff09;&#xff0c;基板管理控制器&#xff0c;普通PC没有&#xff0c;服务器产品必备。BMC是一个独立的系统&#xff0c;只要通电即可运行&#xff0c;服务器无需开机&#xff0c;不依赖其它软硬件&#xff0c;如O…

Unity音频基础概念

一、音源与音频侦听器 游戏画面能够被观众看到&#xff0c;是因为有渲染器和摄像机&#xff0c;同样音频能够被听到&#xff0c;也要有声音的发出者与声音的接收者。声音的发出者叫做音源&#xff0c;接收者叫做音频侦听器。Audio Source与Audio Listener都是组件&#xff0c;…

webrtc 的Bundle group 和RTCP-MUX

1&#xff0c;最近调试程序的时候发现抱一个错误 max-bundle configured but session description has no BUNDLE group 最后发现是一个参数设置错误 config.bundle_policy webrtc::PeerConnectionInterface::BundlePolicy::kBundlePolicyMaxBundle; 2&#xff0c;rtcp-mu…

Linux之Shell(一)

Linux之Shell Shell概述Linux提供的Shell解析器bash和sh的关系Centos默认的解析器是bash Shell脚本入门脚本格式第一个脚本脚本常用的执行方式 变量系统预定义变量自定义变量特殊变量$n$#\$*、\$$? 运算符条件判断流程控制(▲)if判断case语句for循环while循环 read读取控制台输…

macos安装zsh

https://www.cnblogs.com/xuLessReigns/p/11005435.html mac下安装autojump brew install autojump 1&#xff0c;安装zsh&#xff0c;执行 sh -c "$(curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh)" 2&#xff0c;将zsh设置…

并发容器11

一 JDK 提供的并发容器总结 JDK 提供的这些容器大部分在 java.util.concurrent 包中。 ConcurrentHashMap: 线程安全的 HashMap CopyOnWriteArrayList: 线程安全的 List&#xff0c;在读多写少的场合性能非常好&#xff0c;远远好于 Vector. ConcurrentLinkedQueue: 高效的并…

设计模式入门笔记

1 设计模式简介 在IT这个行业&#xff0c;技术日新月异&#xff0c;可能你今年刚弄懂一个编程框架&#xff0c;明年它就不流行了。 然而即使在易变的IT世界也有很多几乎不变的知识&#xff0c;他们晦涩而重要&#xff0c;默默的将程序员划分为卓越与平庸两类。比如说&#xff…

unity 之参数类型之引用类型

文章目录 引用类型引用类型与值类型的差异 引用类型 在Unity中&#xff0c;引用类型是指那些在内存中存储对象引用的数据类型。以下是在Unity中常见的引用类型的介绍&#xff1a; 节点&#xff08;GameObject&#xff09;&#xff1a; 在Unity中&#xff0c;游戏对象&#xff…

无重叠区间【贪心算法】

无重叠区间 给定一个区间的集合 intervals &#xff0c;其中 intervals[i] [starti, endi] 。返回 需要移除区间的最小数量&#xff0c;使剩余区间互不重叠 。 class Solution {public int eraseOverlapIntervals(int[][] intervals) {//先排序&#xff0c;按照左边界升序,注…

【爬虫】实验项目一:文本反爬网站的分析和爬取

目录 一、实验目的 二、实验预习提示 ​编辑 三、实验内容 四、实验要求 五、实验过程 1. 基本要求&#xff1a; 2. 改进要求A 3. 改进要求B: 六、资料 1.实验框架代码&#xff1a; 2.OpenSSL&#xff1a;Win32/Win64 OpenSSL Installer for Windows - Shining Light…

Node与Express后端架构:高性能的Web应用服务

在现代Web应用开发中&#xff0c;后端架构的性能和可扩展性至关重要。Node.js作为一个基于事件驱动、非阻塞I/O的平台&#xff0c;以及Express作为一个流行的Node.js框架&#xff0c;共同构建了高性能的Web应用服务。 在本文中&#xff0c;我们将深入探讨Node与Express后端架构…

Windows笔记本电脑开机黑屏

Windows笔记本电脑开机黑屏 最近&#xff0c;我遇到了一件奇怪的事情。我的Windows笔记本电脑在开机时出现了一个黑屏&#xff0c;没有任何反应。我尝试了多种方法&#xff0c;包括重启和恢复出厂设置&#xff0c;但都无济于事。 我开始感到担心&#xff0c;因为这只会影响到…

污水厂数字孪生 | 3D可视化管理系统助力污水企业数字化管理

随着城市化进程的不断加快&#xff0c;污水处理成为了城市环境保护的重要组成部分。传统的污水处理方式往往存在诸多问题&#xff0c;如信息不对称、安全隐患等。为了解决这些问题&#xff0c;污水处理3D可视化管控平台应运而生&#xff0c;它通过结合数字孪生技术和远程指导技…

【行为树】py_trees 学习笔记

学习资料 《Introduction to behavior trees》 1. 概念说明 1.1 Action&#xff1a;pt.behaviour.Behaviour 在一个行为树中&#xff0c;Action 是一个叶节点&#xff08;Leaf Node&#xff09;&#xff0c;它实际执行某种行为或任务&#xff0c;并返回成功、失败或运行中的…

Unity关键概念

Unity是一款跨平台的游戏引擎和开发工具&#xff0c;用于创建2D和3D游戏、交互式内容和应用程序。它提供了一个强大的开发环境&#xff0c;使开发者能够轻松地设计、开发和部署高质量的游戏和应用程序。 以下是Unity的几个关键概念&#xff1a; 游戏对象&#xff08;Game Obj…

【逻辑运算符】在Java中 和的区别 ||和|的区别

&&和&都表示与运算符&#xff0c;结果为有假则假&#xff0c;&&为短路与运算符&#xff0c;如果表达式A的值为假&#xff0c;则表达式B不执行;&表示逻辑与运算符&#xff0c;表达式A和表达式B都会执行 ||和|都表示或运算符&#xff0c;结果为有真则真&…