React学习笔记
描述UI
组件
React 组件是常规的 JavaScript 函数,但 组件的名称必须以大写字母开头,否则它们将无法运行!
定义一个react组件。
1 | function Hello(){ |
如果你的标签和 **return** 关键字不在同一行,则必须把它包裹在一对括号中。没有括号包裹的话,任何在 return 下一行的代码都 将被忽略!
组件的导入和导出
组件的导出主要分为具名导出和默认导出,默认导出在一个文件中只能有一个。
语法 | 导出语句 | 导入语句 |
---|---|---|
默认 | export default function Button() {} | import Button from ‘./Button.js’; |
具名 | export function Button() {} | import { Button } from ‘./Button.js’; |
JSX书写标签语言
JSX and React 是相互独立的 东西。但它们经常一起使用,但你 可以 单独使用它们中的任意一个,JSX 是一种语法扩展,而 React 则是一个 JavaScript 的库。
- 只能返回一个根元素。
如果想要在一个组件中包含多个元素,需要用一个父标签把它们包裹起来。
如果你不想在标签中增加一个额外的<div>
,可以用<>
和</>
元素来代替。
为什么多个 JSX 标签需要被一个父元素包裹?
JSX 虽然看起来很像 HTML,但在底层其实被转化为了 JavaScript 对象,你不能在一个函数中返回多个对象,除非用一个数组把他们包装起来。这就是为什么多个 JSX 标签必须要用一个父元素或者 Fragment 来包裹。
- 标签必须闭合。
JSX 要求标签必须正确闭合。像<img>
这样的自闭合标签必须书写成<img />
,而像<li>oranges
这样只有开始标签的元素必须带有闭合标签,需要改为<li>oranges</li>
。
- 使用驼峰式命名法给
所有大部分属性命名
在 React 中,大部分 HTML 和 SVG 属性都用驼峰式命名法表示。例如,需要用 strokeWidth 代替 stroke-width。由于 class 是一个保留字,所以在 React 中需要用 className 来代替。
在 JSX 中通过大括号使用 JavaScript
在 JSX 中,只能在以下两种场景中使用大括号:
- 用作 JSX 标签内的文本:
<h1>{name}'s To Do List</h1>
是有效的,但是<{tag}>Gregorio Y. Zara's To Do List</{tag}>
无效。 - 用作紧跟在
=
符号后的 属性:src={avatar}
会读取 avatar 变量,但是src="{avatar}"
只会传一个字符串{avatar}
。
传递Props
React 组件使用 props 来互相通信。每个父组件都可以提供 props 给它的子组件,从而将一些信息传递给它。
父组件传递props:
1 | export default function Profile() { |
子组件读取props:这里使用了解构语法。
1 | function Avatar({ person, size }) { |
如果你想在没有指定值的情况下给 prop 一个默认值,你可以通过在参数后面写 = 和默认值来进行解构:
1 | function Avatar({ person, size = 90 }) { |
默认值仅在缺少size
prop 或size={undefined}
时生效。 但是如果你传递了size={null}
或size={0}
,默认值将 不 被使用。
子组件传递。将父组件包裹的内容渲染出来。
父组件将在名为children
的 prop 中接收到该内容。例如,下面的Card
组件将接收一个被设为 <Avatar />
的children
prop 并将其包裹在 div 中渲染:
1 | function Card({ children }) { |
条件渲染
在 React 中,你可以通过使用 JavaScript 的<font style="color:rgb(35, 39, 47);"> </font>if<font style="color:rgb(35, 39, 47);"> </font>
语句、&&<font style="color:rgb(35, 39, 47);"> </font>
和 ? :<font style="color:rgb(35, 39, 47);"> </font>
运算符来选择性地渲染 JSX。
<font style="color:rgb(35, 39, 47);">if</font>
:
1 | function Item({ name, isPacked }) { |
? :
:
1 | return ( |
&&
:
1 | function Item({ name, isPacked }) { |
切勿将数字放在 **&&** 左侧.
JavaScript 会自动将左侧的值转换成布尔类型以判断条件成立与否。然而,如果左侧是 0,整个表达式将变成左侧的值(0),React 此时则会渲染 0 而不是不进行渲染。
渲染列表
使用map渲染列表。
1 | const people = [ |
如果你想让每个列表项都输出多个 DOM 节点而非一个的话,该怎么做呢?
Fragment 语法的简写形式 <> </>
无法接受 key 值,所以你只能要么把生成的节点用一个
1 | import { Fragment } from 'react'; |
这里的 Fragment 标签本身并不会出现在 DOM 上,这串代码最终会转换成 <h1>
、<p>
、<h1>
、<p>
…… 的列表。
key值具有唯一标识一个信息的能力,但不能是随机值。
添加交互
添加响应事件
1 | export default function Button() { |
传递给事件处理函数的函数应直接传递,而非调用。例如:
传递一个函数(正确) | 调用一个函数(错误) |
---|---|
区别很微妙。在第一个示例中,handleClick 函数作为 onClick 事件处理函数传递。这会让 React 记住它,并且只在用户点击按钮时调用你的函数。
在第二个示例中,handleClick() 中最后的 () 会在 渲染 过程中 立即 触发函数,即使没有任何点击。这是因为在 JSX { 和 } 之间的 JavaScript 会立即执行。
当你编写内联代码时,同样的陷阱可能会以不同的方式出现:
传递一个函数(正确) | 调用一个函数(错误) |
---|---|
<button onClick={() => alert(‘…’)}> | <button onClick={alert(‘…’)}> |
事件处理函数还将捕获任何来自子组件的事件。通常,我们会说事件会沿着树向上“冒泡”或“传播”:它从事件发生的地方开始,然后沿着树向上传播。
如果你想阻止一个事件到达父组件,你需要像下面 Button 组件那样调用 e.stopPropagation() :
1 | function Button({ onClick, children }) { |
某些浏览器事件具有与事件相关联的默认行为。例如,点击