Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs(cn): translate reference/react/forwardRef into Chinese #1147

Merged
merged 32 commits into from
Jun 10, 2023
Merged
Changes from 7 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
ce2c5b4
docs(cn): translate reference/react/forwardRef into Chinese
Woodii1998 Apr 29, 2023
efa6c71
Merge branch 'main' into forwardRef
Woodii1998 Apr 29, 2023
a26387c
fix: formatting errors
Woodii1998 Apr 29, 2023
94643d8
Merge branch 'forwardRef' of https://github.com/Woodii1998/zh-hans.re…
Woodii1998 Apr 29, 2023
5705749
fix: formatting errors
Woodii1998 Apr 29, 2023
fbeaae1
fix
awxiaoxian2020 Apr 29, 2023
1693d64
Merge branch 'main' into forwardRef
Woodii1998 May 1, 2023
114fa72
Update src/content/reference/react/forwardRef.md
Woodii1998 May 6, 2023
99939d6
Update src/content/reference/react/forwardRef.md
Woodii1998 May 6, 2023
530ac15
Update src/content/reference/react/forwardRef.md
Woodii1998 May 6, 2023
f0e8b3e
Update src/content/reference/react/forwardRef.md
Woodii1998 May 6, 2023
4a5549f
Merge branch 'main' into forwardRef
Woodii1998 May 6, 2023
535c801
Update src/content/reference/react/forwardRef.md
Woodii1998 May 23, 2023
9205f9b
Update src/content/reference/react/forwardRef.md
Woodii1998 May 23, 2023
6e674fc
Update src/content/reference/react/forwardRef.md
Woodii1998 May 23, 2023
4a4b801
Update src/content/reference/react/forwardRef.md
Woodii1998 May 23, 2023
ebec732
Update src/content/reference/react/forwardRef.md
Woodii1998 May 23, 2023
e1eaf4d
Update src/content/reference/react/forwardRef.md
Woodii1998 May 23, 2023
bea42ad
Update src/content/reference/react/forwardRef.md
Woodii1998 May 23, 2023
e6f161e
Update src/content/reference/react/forwardRef.md
Woodii1998 May 23, 2023
773b1ce
Update src/content/reference/react/forwardRef.md
Woodii1998 May 23, 2023
6161cb8
Update src/content/reference/react/forwardRef.md
Woodii1998 May 23, 2023
e2d19dc
Update src/content/reference/react/forwardRef.md
Woodii1998 May 23, 2023
6268bde
Update src/content/reference/react/forwardRef.md
Woodii1998 May 23, 2023
8b750ba
Update src/content/reference/react/forwardRef.md
Woodii1998 May 23, 2023
0fe6fa3
Update src/content/reference/react/forwardRef.md
Woodii1998 May 23, 2023
bbb9228
Update src/content/reference/react/forwardRef.md
Woodii1998 May 23, 2023
fdcafc3
Update src/content/reference/react/forwardRef.md
Woodii1998 May 23, 2023
21f8a5c
Merge branch 'main' into forwardRef
Woodii1998 May 23, 2023
8d8976e
Merge branch 'main' into forwardRef
Woodii1998 Jun 1, 2023
c315a09
Update src/content/reference/react/forwardRef.md
Yucohny Jun 10, 2023
52c7e62
Update src/content/reference/react/forwardRef.md
Yucohny Jun 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 46 additions & 46 deletions src/content/reference/react/forwardRef.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ title: forwardRef

<Intro>

`forwardRef` lets your component expose a DOM node to parent component with a [ref.](/learn/manipulating-the-dom-with-refs)
`forwardRef` 允许你的组件使用 [ref](/learn/manipulating-the-dom-with-refs) 将一个 DOM 节点暴露给父组件。

```js
const SomeComponent = forwardRef(render)
Expand All @@ -16,11 +16,11 @@ const SomeComponent = forwardRef(render)

---

## Reference {/*reference*/}
## 参考 {/*reference*/}

### `forwardRef(render)` {/*forwardref*/}

Call `forwardRef()` to let your component receive a ref and forward it to a child component:
使用 `forwardRef()` 来让你的组件接收一个 ref 并将其传递给一个子组件:

```js
import { forwardRef } from 'react';
Expand All @@ -30,26 +30,26 @@ const MyInput = forwardRef(function MyInput(props, ref) {
});
```

[See more examples below.](#usage)
[请看下面的更多例子](#usage)

#### Parameters {/*parameters*/}
#### 参数 {/*parameters*/}

* `render`: The render function for your component. React calls this function with the props and `ref` that your component received from its parent. The JSX you return will be the output of your component.
* `render`:组件的渲染函数。React 会调用该函数并传入父组件传递来的参数和 `ref`。返回的 JSX 将成为组件的输出。

#### Returns {/*returns*/}
#### 返回值 {/*returns*/}

`forwardRef` returns a React component that you can render in JSX. Unlike React components defined as plain functions, a component returned by `forwardRef` is also able to receive a `ref` prop.
`forwardRef` 返回一个可以在 JSX 中渲染的 React 组件。与作为纯函数定义的 React 组件不同,`forwardRef` 返回的组件还能够接收 `ref` 属性。

#### Caveats {/*caveats*/}
#### 警告 {/*caveats*/}

* In Strict Mode, React will **call your render function twice** in order to [help you find accidental impurities.](#my-initializer-or-updater-function-runs-twice) This is development-only behavior and does not affect production. If your render function is pure (as it should be), this should not affect the logic of your component. The result from one of the calls will be ignored.
* 在严格模式中,为了 [帮助你找到意外的副作用](#my-initializer-or-updater-function-runs-twice) React 将会**调用你的渲染函数两次**,这仅限于开发环境,并不影响生产环境。如果你的渲染函数是纯函数(也应该是),这应该不会影响你的组件逻辑。其中一个调用的结果将被忽略。
Woodii1998 marked this conversation as resolved.
Show resolved Hide resolved


---

### `render` function {/*render-function*/}
### `render` 函数 {/*render-function*/}

`forwardRef` accepts a render function as an argument. React calls this function with `props` and `ref`:
`forwardRef` 接受一个渲染函数作为参数。React 将会使用 `props` `ref` 调用此函数:

```js
const MyInput = forwardRef(function MyInput(props, ref) {
Expand All @@ -62,23 +62,23 @@ const MyInput = forwardRef(function MyInput(props, ref) {
});
```

#### Parameters {/*render-parameters*/}
#### 参数 {/*render-parameters*/}

* `props`: The props passed by the parent component.
* `props`:父组件传递过来的参数。

* `ref`: The `ref` attribute passed by the parent component. The `ref` can be an object or a function. If the parent component has not passed a ref, it will be `null`. You should either pass the `ref` you receive to another component, or pass it to [`useImperativeHandle`.](/reference/react/useImperativeHandle)
* `ref`:父组件传递的 `ref` 属性。`ref` 可以是一个对象或者是一个函数。如果父组件没有传递一个 ref,那么它将会是 `null`。你应该将接收到的 `ref` 转发给另一个组件,或者将其传递给 [`useImperativeHandle`](/reference/react/useImperativeHandle)
Woodii1998 marked this conversation as resolved.
Show resolved Hide resolved

#### Returns {/*render-returns*/}
#### 返回值 {/*render-returns*/}

`forwardRef` returns a React component that you can render in JSX. Unlike React components defined as plain functions, the component returned by `forwardRef` is able to take a `ref` prop.
`forwardRef` 返回一个可以在 JSX 中渲染的 React 组件。与作为纯函数定义的React组件不同,`forwardRef` 返回的组件还能够接收 `ref` 属性。
Woodii1998 marked this conversation as resolved.
Show resolved Hide resolved

---

## Usage {/*usage*/}
## 用法 {/*usage*/}

### Exposing a DOM node to the parent component {/*exposing-a-dom-node-to-the-parent-component*/}
### DOM 节点暴露给父组件 {/*exposing-a-dom-node-to-the-parent-component*/}

By default, each component's DOM nodes are private. However, sometimes it's useful to expose a DOM node to the parent--for example, to allow focusing it. To opt in, wrap your component definition into `forwardRef()`:
默认情况下,每个组件的 DOM 节点都是私有的。然而,有时候将 DOM 节点公开给父组件是很有用的,比如允许对它进行聚焦。要选择公开,可以将组件定义包装在 `forwardRef()` 中:
Woodii1998 marked this conversation as resolved.
Show resolved Hide resolved

```js {3,11}
import { forwardRef } from 'react';
Expand All @@ -94,7 +94,7 @@ const MyInput = forwardRef(function MyInput(props, ref) {
});
```

You will receive a <CodeStep step={1}>ref</CodeStep> as the second argument after props. Pass it to the DOM node that you want to expose:
你将在props之后收到一个 <CodeStep step={1}>ref</CodeStep> 作为第二个参数。将其传递到要公开的 DOM 节点中:
Woodii1998 marked this conversation as resolved.
Show resolved Hide resolved

```js {8} [[1, 3, "ref"], [1, 8, "ref", 30]]
import { forwardRef } from 'react';
Expand All @@ -110,7 +110,7 @@ const MyInput = forwardRef(function MyInput(props, ref) {
});
```

This lets the parent `Form` component access the <CodeStep step={2}>`<input>` DOM node</CodeStep> exposed by `MyInput`:
这样,父级的 `Form` 组件就能够访问 `MyInput` 暴露的 <CodeStep step={2}>`<input>` DOM 节点</CodeStep>

```js [[1, 2, "ref"], [1, 10, "ref", 41], [2, 5, "ref.current"]]
function Form() {
Expand All @@ -131,15 +131,15 @@ function Form() {
}
```

This `Form` component [passes a ref](/reference/react/useRef#manipulating-the-dom-with-a-ref) to `MyInput`. The `MyInput` component *forwards* that ref to the `<input>` browser tag. As a result, the `Form` component can access that `<input>` DOM node and call [`focus()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus) on it.
这个 `Form` 组件给 `MyInput` [传递了一个 ref](/reference/react/useRef#manipulating-the-dom-with-a-ref)`MyInput` 组件**转发**了该 ref `<input>` 浏览器标签。因此, `Form` 组件可以访问该 `<input>` DOM 节点并对其调用 [`focus()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus)
Woodii1998 marked this conversation as resolved.
Show resolved Hide resolved

Keep in mind that exposing a ref to the DOM node inside your component makes it harder to change your component's internals later. You will typically expose DOM nodes from reusable low-level components like buttons or text inputs, but you won't do it for application-level components like an avatar or a comment.
请记住,将组件内部的 ref 暴露给 DOM 节点会使得在稍后更改组件内部更加困难。通常,你会将 DOM 节点从可重用的低级组件中暴露出来,例如按钮或文本输入框,但不会在应用程序级别的组件中这样做,例如头像或评论。

<Recipes title="Examples of forwarding a ref">

#### Focusing a text input {/*focusing-a-text-input*/}
#### 聚焦文本输入框 {/*focusing-a-text-input*/}

Clicking the button will focus the input. The `Form` component defines a ref and passes it to the `MyInput` component. The `MyInput` component forwards that ref to the browser `<input>`. This lets the `Form` component focus the `<input>`.
点击该按钮将聚焦输入框。`Form` 组件定义了一个 ref 并将其传递到 `MyInput` 组件。 MyInput 组件将该 ref 转发给浏览器的 `<input>` 标签,这使得 `Form` 组件可以聚焦该 `<input>`
Woodii1998 marked this conversation as resolved.
Show resolved Hide resolved

<Sandpack>

Expand Down Expand Up @@ -191,9 +191,9 @@ input {

<Solution />

#### Playing and pausing a video {/*playing-and-pausing-a-video*/}
#### 播放和暂停视频 {/*playing-and-pausing-a-video*/}

Clicking the button will call [`play()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/play) and [`pause()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/pause) on a `<video>` DOM node. The `App` component defines a ref and passes it to the `MyVideoPlayer` component. The `MyVideoPlayer` component forwards that ref to the browser `<video>` node. This lets the `App` component play and pause the `<video>`.
点击按钮将调用 `<video>` DOM 节点上的 [`play()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/play) [`pause()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/pause) 方法。`App` 组件定义了一个 ref 并将其传递到 `MyVideoPlayer` 组件。`MyVideoPlayer` 组件将该 ref 转发到浏览器的 `<video>` 标签。这使得 `App` 组件可以播放和暂停 `<video>`
Woodii1998 marked this conversation as resolved.
Show resolved Hide resolved

<Sandpack>

Expand Down Expand Up @@ -252,9 +252,9 @@ button { margin-bottom: 10px; margin-right: 10px; }

---

### Forwarding a ref through multiple components {/*forwarding-a-ref-through-multiple-components*/}
### 在多个组件中转发 ref {/*forwarding-a-ref-through-multiple-components*/}

Instead of forwarding a `ref` to a DOM node, you can forward it to your own component like `MyInput`:
除了将 `ref` 转发到 DOM 节点外,你还可以将其转发到你自己的组件,例如 `MyInput` 组件:

```js {1,5}
const FormField = forwardRef(function FormField(props, ref) {
Expand All @@ -268,7 +268,7 @@ const FormField = forwardRef(function FormField(props, ref) {
});
```

If that `MyInput` component forwards a ref to its `<input>`, a ref to `FormField` will give you that `<input>`:
如果 `MyInput` 组件将 ref 转发给它的 `<input>`,那么对于 `FormField` 的 ref 将会获得该 `<input>`
Woodii1998 marked this conversation as resolved.
Show resolved Hide resolved

```js {2,5,10}
function Form() {
Expand All @@ -289,7 +289,7 @@ function Form() {
}
```

The `Form` component defines a ref and passes it to `FormField`. The `FormField` component forwards that ref to `MyInput`, which forwards it to a browser `<input>` DOM node. This is how `Form` accesses that DOM node.
`Form` 组件定义了一个 ref 并将其传递给 `FormField``FormField` 组件将该 ref 转发给 `MyInput`,后者又将其转发给浏览器的 `<input>` DOM 节点。 这就是 `Form` 获取该DOM节点的方式。
Woodii1998 marked this conversation as resolved.
Show resolved Hide resolved


<Sandpack>
Expand Down Expand Up @@ -367,9 +367,9 @@ input, button {

---

### Exposing an imperative handle instead of a DOM node {/*exposing-an-imperative-handle-instead-of-a-dom-node*/}
### 暴露一个命令式句柄而不是 DOM 节点 {/*exposing-an-imperative-handle-instead-of-a-dom-node*/}

Instead of exposing an entire DOM node, you can expose a custom object, called an *imperative handle,* with a more constrained set of methods. To do this, you'd need to define a separate ref to hold the DOM node:
可以使用一个被称为**命令式句柄(imperative handle)**的自定义对象来暴露一个更加受限制的方法集,而不是暴露整个 DOM 节点。为了实现这个目的,你需要定义一个单独的 ref 来存储 DOM 节点:
Woodii1998 marked this conversation as resolved.
Show resolved Hide resolved

```js {2,6}
const MyInput = forwardRef(function MyInput(props, ref) {
Expand All @@ -381,7 +381,7 @@ const MyInput = forwardRef(function MyInput(props, ref) {
});
```

Pass the `ref` you received to [`useImperativeHandle`](/reference/react/useImperativeHandle) and specify the value you want to expose to the `ref`:
将你收到的 `ref` 传递给 [`useImperativeHandle`](/reference/react/useImperativeHandle) 并指定你想要暴露给 `ref` 的值:
Woodii1998 marked this conversation as resolved.
Show resolved Hide resolved

```js {6-15}
import { forwardRef, useRef, useImperativeHandle } from 'react';
Expand All @@ -404,7 +404,7 @@ const MyInput = forwardRef(function MyInput(props, ref) {
});
```

If some component gets a ref to `MyInput`, it will only receive your `{ focus, scrollIntoView }` object instead of the DOM node. This lets you limit the information you expose about your DOM node to the minimum.
如果某个组件得到了 `MyInput` 的 ref, 则只会接收到你的 `{ focus, scrollIntoView }` 对象,而不是整个 DOM 节点。这可以让你的 DOM 节点暴露的信息限制到最小。
Woodii1998 marked this conversation as resolved.
Show resolved Hide resolved

<Sandpack>

Expand All @@ -417,7 +417,7 @@ export default function Form() {

function handleClick() {
ref.current.focus();
// This won't work because the DOM node isn't exposed:
// 这行代码不起作用,因为 DOM 节点没有被暴露出来:
// ref.current.style.opacity = 0.5;
}

Expand Down Expand Up @@ -463,25 +463,25 @@ input {

</Sandpack>

[Read more about using imperative handles.](/reference/react/useImperativeHandle)
[了解更多关于使用命令式句柄的内容](/reference/react/useImperativeHandle)

<Pitfall>

**Do not overuse refs.** You should only use refs for *imperative* behaviors that you can't express as props: for example, scrolling to a node, focusing a node, triggering an animation, selecting text, and so on.
**不要滥用 refs** 只有对于作为 props 无法表达的**命令式**行为才应该使用 refs:例如滚动到节点、将焦点放在节点上、触发动画、选择文本等等。
Woodii1998 marked this conversation as resolved.
Show resolved Hide resolved

**If you can express something as a prop, you should not use a ref.** For example, instead of exposing an imperative handle like `{ open, close }` from a `Modal` component, it is better to take `isOpen` as a prop like `<Modal isOpen={isOpen} />`. [Effects](/learn/synchronizing-with-effects) can help you expose imperative behaviors via props.

**如果你可以把某些东西表达为 props,就不应该使用 refs。** 例如,不要从一个 Modal 组件中暴露一个命令式的句柄,如 `{ open, close }`,更好的做法是像这样使用 isOpen 作为一个 prop `<Modal isOpen={isOpen} />`. [Effects](/learn/synchronizing-with-effects) 可以帮助你通过 props 暴露命令式行为。
Woodii1998 marked this conversation as resolved.
Show resolved Hide resolved
</Pitfall>

---

## Troubleshooting {/*troubleshooting*/}

### My component is wrapped in `forwardRef`, but the `ref` to it is always `null` {/*my-component-is-wrapped-in-forwardref-but-the-ref-to-it-is-always-null*/}
### 我的组件使用了 `forwardRef`,但是它的 `ref` 总是为 `null` {/*my-component-is-wrapped-in-forwardref-but-the-ref-to-it-is-always-null*/}

This usually means that you forgot to actually use the `ref` that you received.
这通常意味着你忘记实际使用你所接收到的 `ref` 了。

For example, this component doesn't do anything with its `ref`:
例如,这个组件的 `ref` 没有被使用:

```js {1}
const MyInput = forwardRef(function MyInput({ label }, ref) {
Expand All @@ -494,7 +494,7 @@ const MyInput = forwardRef(function MyInput({ label }, ref) {
});
```

To fix it, pass the `ref` down to a DOM node or another component that can accept a ref:
为了修复它,将 `ref` 传递给一个可以接受 ref 的 DOM 节点或另一个组件:
Woodii1998 marked this conversation as resolved.
Show resolved Hide resolved

```js {1,5}
const MyInput = forwardRef(function MyInput({ label }, ref) {
Expand All @@ -507,7 +507,7 @@ const MyInput = forwardRef(function MyInput({ label }, ref) {
});
```

The `ref` to `MyInput` could also be `null` if some of the logic is conditional:
如果某些逻辑是有条件的,`MyInput` 的 `ref` 可能也会为 `null`

```js {1,5}
const MyInput = forwardRef(function MyInput({ label, showInput }, ref) {
Expand All @@ -520,7 +520,7 @@ const MyInput = forwardRef(function MyInput({ label, showInput }, ref) {
});
```

If `showInput` is `false`, then the ref won't be forwarded to any node, and a ref to `MyInput` will remain empty. This is particularly easy to miss if the condition is hidden inside another component, like `Panel` in this example:
如果 `showInput` `false`,则 `ref` 将不会被转发到任何节点,并且 `MyInput` 的 ref 会保持为空。如果这个条件隐藏在另一个组件中,那么很容易忽略这一点,比如这个例子中的 Panel
Woodii1998 marked this conversation as resolved.
Show resolved Hide resolved

```js {5,7}
const MyInput = forwardRef(function MyInput({ label, showInput }, ref) {
Expand Down