Skip to content
This page has been auto-translated and may contain errors.View in English

组件

假设一个页面需要在三个地方显示同一张问候卡片,每处都有相同的标题和布局。如果复制标记三次,那么每当设计改变时,你就要在三个地方同时更新。React 的解决方案是只写一次这段 UI,然后把它作为 组件 重复使用:一个返回 JSX(UI 描述)的 JavaScript 函数。你可以像使用 HTML 标签一样使用它,React 会调用这个函数来确定在屏幕上显示什么。

这是最小的例子:

jsx
function Greeting() {
  return <h1>Hello</h1>
}

Greeting 是一个返回 <h1>Hello</h1> 的函数。要真正把它显示出来,你需要在另一个组件内渲染它,像使用标签一样使用它:

jsx
function App() {
  return (
    <div>
      <Greeting />
      <Greeting />
    </div>
  )
}

App 也是一个组件。它在一个 div 内渲染两个 Greeting 组件,每个都输出自己的 <h1>Hello</h1>。这就是组合:你构建小组件,再把它们组合成更大的组件,直到组成一整个应用。

这有几条规则要遵守。组件名必须以大写字母开头。GreetingApp 能作为标签工作,是因为 React 能把它们和普通的 HTML 元素(如 divh1)区分开来,而后者以小写字母开头。返回 JSX 的组件还必须返回一个单一的根元素,就像 App 用一个外层 div 包裹它的两个 Greeting 标签一样。很多人第一次都会在这里跌跟头:如果你返回两个相邻的元素而不把它们包裹在一个 div 中,React 会抛出错误。如果你需要返回相邻元素而不想用额外的 div 包裹,可以使用 fragment:

jsx
function Greeting() {
  return (
    <>
      <h1>Hello</h1>
      <p>Welcome back</p>
    </>
  )
}

<></> 是一个 fragment。它把 h1p 组合成一个返回值,而不在页面上添加任何元素。

版本说明

老版本的 React 代码通常使用类来定义组件,而不是函数:

jsx
class Greeting extends React.Component {
  render() {
    return <h1>Hello</h1>
  }
}

你在现有的代码库中仍然会看到这样的类组件。这个教程始终使用函数组件,那是现在标准的 React 写法。参考 History and versions 了解 React 是如何从一种风格演变到另一种的。

组件在渲染期间被调用,所以要把函数体纯粹当作计算的地方,不要在其中产生副作用。给定相同的 props,一个组件每次都应该返回相同的 JSX。不要在函数体中直接获取数据、设置计时器或修改函数外部的变量。这些操作属于像 useEffect 这样的 hook(后面在 Effects 中讲解),它在渲染完成后才运行,而不是在渲染期间。读取 DOM、写入在组件外部声明的变量,或依赖于在调用间改变的值,都会破坏这一原则,导致很难追踪的 bug,因为 React 可能会因为你无法控制的原因多次调用你的组件。

Juno组件是一个函数 整个概念可以用一句话总结:组件是一个函数,用像 <Greeting /> 这样的标签调用它会运行这个函数并显示它的返回值。一旦理解了这一点,React 的其他部分就是学习在这些函数内部可以放什么。
Juno组件是一个函数 在 React 中,组件是你进行构建的基本单位。保持它们小而专注,用大写字母命名,返回一个单一的根元素,在需要组合相邻元素而不想添加额外包裹元素时使用 fragment。组合,即把小组件组合成更大的组件,就是构建每一个真实界面的方式。
Juno组件是一个函数 组件是其 props 的纯函数:相同的输入产生相同的 JSX,函数体中没有副作用。正是这个约束让 React 可以自由地调用你的组件、批处理渲染以及重排工作而不会出错。副作用有专门的 hook 是有原因的。

接下来:JSX,你在这些 return 语句中看到的语法。