Skip to main content

组件语法

组件 是在 React 中构建 UI 的基础。虽然组件通常使用 JavaScript 函数来表达,但组件语法提供了组件原始值,这些值比函数组件具有多种优势,例如:

¥Components are the foundation for building UIs in React. While components are typically expressed using JavaScript functions, Component Syntax provides component primitive values that provide several advantages over function components, like:

  1. 与函数相比,语法更优雅,冗长和样板代码明显更少

    ¥More elegant syntax with significantly less verbosity and boilerplate than functions

  2. 专门为编写 React 定制的类型系统支持

    ¥Type system support tailored specifically for writing React

  3. 更好地支持 反应参考

    ¥Better support for React refs

基本用法

¥Basic Usage

你可以使用组件语法声明组件,类似于声明函数的方式:

¥You can declare a component with Component Syntax similar to how you'd declare a function:

1import * as React from 'react';2
3component Introduction(name: string, age: number) {4  return <h1>My name is {name} and I am {age} years old</h1>5}

你可以直接在 JSX 中使用组件:<Introduction age={9} name="Mr. Flow" />

¥You can use a component directly in JSX: <Introduction age={9} name="Mr. Flow" />.

这里有一些重要的细节需要注意:

¥There are a few important details to notice here:

  1. 在 Introduction 组件中声明的 prop 参数名称与在 JSX 中传递给 Introduction 的 prop 名称相同

    ¥the prop parameter names declared in the Introduction component are the same as the prop names passed to Introduction in JSX

  2. 声明中参数的顺序不需要与 JSX 中提供的顺序匹配

    ¥the order of the parameters in the declaration does not need to match the order that they are provided in JSX

参数

¥Parameters

字符串参数/重命名参数

¥String Parameters/Renaming Parameters

组件还允许你重命名参数,当你的参数名称不是有效的 JavaScript 标识符时,这非常有用:

¥Components also allow you to rename parameters, which is useful when your parameter name is not a valid JavaScript identifier:

1import * as React from 'react';2
3component RenamedParameter(4  'required-renamed' as foo: number,5  'optional-renamed' as bar?: number,6  'optional-with-default-renamed' as baz?: number = 3,7) {8  (foo: number); // OK9  (bar: number | void); // OK10  (baz: number); // OK11
12  return <div />;13}

其余参数

¥Rest Parameters

有时你不想显式列出每个 prop,因为你不打算在组件中单独引用它们。当你编写一个封装另一个组件并需要将 props 从你的组件传递到内部组件时,这种情况很常见:

¥Sometimes you do not want to list out every prop explicitly because you do not intend to reference them individually in your component. This is common when you are writing a component that wraps another and need to pass props from your component to the inner one:

import * as React from 'react';

import type {Props as StarProps} from './Star';
import Star from './Star';

component BlueStar(...props: StarProps) {
return <Star {...props} color="blue" />;
}

其余参数使用对象类型作为注释,这意味着你可以使用现有的类型实用程序(例如对象扩展和 Pick)来注释更复杂的 prop 模式:

¥Rest parameters use an object type as an annotation, which means you can use existing type utilities like object spreads and Pick to annotate more complex prop patterns:

1import * as React from 'react';2
3component OtherComponent(foo: string, bar: number) {4  return foo + bar;5}6
7component FancyProps(8  ...props: {9    ...React.PropsOf<OtherComponent>,10    additionalProp: string,11  }12) {13  return <OtherComponent foo={props.foo} bar={props.bar} />;14}

可选参数和默认值

¥Optional Parameters and Defaults

组件允许你声明可选参数并指定默认值:

¥Components allow you to declare optional parameters and specify defaults:

1import * as React from 'react';2
3component OptionalAndDefaults(4  color: string = "blue",5  extraMessage?: string,6) {7  let message = `My favorite color is ${color}.`;8  if (extraMessage != null) {9    message += `\n${extraMessage}`;10  }11  return <p>{message}</p>12}13
14<OptionalAndDefaults /> // No error, all of the parameters are optional!

解构参数

¥Destructuring Parameters

as 运算符还允许你解构参数:

¥The as operator also allows you to destructure your parameters:

1import * as React from 'react';2
3component Destructuring(4  config as {color, height}: $ReadOnly<{color: number, height: number}>,5) { return <div /> }

剩余参数可以在不使用 as 的情况下进行解构:

¥Rest parameters can be destructured without using as:

1import * as React from 'react';2
3type Props = $ReadOnly<{ color: string, height: number }>;4
5component DestructuredRest(...{color, height}: Props) { return <div /> }

参考参数

¥Ref Parameters

要访问组件中的引用,你只需添加一个 ref 参数。

¥To access refs in components you just need to add a ref parameter.

1import * as React from 'react';2
3component ComponentWithARef(ref: React.RefSetter<HTMLElement>) {4  return <div ref={ref} />;5}

在幕后,组件语法会将组件封装在所需的 React.forwardRef 调用 中,以确保组件在运行时按预期工作。refs 的一个限制是它们必须定义为内联参数,不支持剩余参数内的 refs。这是因为需要在 forwardRef 调用中进行编译,为了使其正常工作,我们需要能够静态地确定组件定义中的引用。

¥Behind the scenes Component Syntax will wrap the component in the required React.forwardRef call to ensure the component works as expected at runtime. The one restriction for refs is they must be defined as an inline parameter, refs within rest params are not supported. This is due to the need to compile in the forwardRef call, for this to work correctly we need to be able to statically determine the ref from the component definition.

组件的元素

¥Elements of Components

对于在组件语法中声明的组件,你可以使用 ComponentName 来引用该组件的元素的类型。对于不使用组件语法的组件,你必须编写 React.Element<typeof ComponentName>

¥For components declared in Component Syntax, you can use ComponentName to reference the type of an element of that component. For components not using Component Syntax you have to write React.Element<typeof ComponentName>.

1import * as React from 'react';2
3declare component Foo();4declare component Bar();5
6const foo: Foo = <Foo />;7const bar: Bar = <Foo />; // ERROR

该语法也适用于通用组件:

¥The syntax also works for generic components:

1import * as React from 'react';2
3declare component Foo<T>(prop: T);4
5const foo1: Foo<string> = <Foo prop="" />;6const foo2: Foo<number> = <Foo prop="" />; // Invalid generic type argument7const foo3: Foo = <Foo prop="" />; // Missing generic type argument

我们不建议需要非常特定类型的元素。它将使你的父组件和子组件更加耦合。相反,此功能旨在使 渲染类型 的表达更容易。

¥We do not recommend requiring very specific type of elements. It will make your parent and children components more coupled. Instead, this feature is designed to make expressing render types easier.

组件规则

¥Rules for Components

组件语法在组件中强制执行一些限制,以帮助确保正确性:

¥Component Syntax enforces a few restrictions in components to help ensure correctness:

  1. 返回值必须是 React.Node 的子类型,否则 React 可能会在渲染组件时崩溃。

    ¥The return values must be a subtype of React.Node, otherwise React may crash while rendering your component.

  2. 组件的所有分支必须以显式返回结束。尽管 undefined 是有效的返回值,但我们已经看到许多显式返回可以防止生产中出现错误的情况。

    ¥All branches of a component must end in an explicit return. Even though undefined is a valid return value, we've seen many instances where an explicit return would have prevented bugs in production.

  3. 你不能在组件中使用 this

    ¥You cannot use this in a component.

所以这些组件是无效的:

¥So these components are invalid:

1import * as React from 'react';2
3component InvalidReturnValue() {4  return new Object(); // ERROR: Value does not match `React.Node` type5}6
7component ImplicitReturn(someCond: boolean) {8  if (someCond) {9    return <h1>Hello World!</h1>;10  }11  // ERROR: No return in this branch12}13
14component UsesThis() {15  this.foo = 3; // ERROR: Accessing `this`16  return null;17}

启用组件语法

¥Enable Component Syntax

在你的 .flowconfig 中,在 [options] 标题下,添加 component_syntax=true

¥In your .flowconfig, under the [options] heading, add component_syntax=true.