Skip to content
New issue

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

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

Already on GitHub? # to your account

docs(cn): translate content/docs/forwarding-refs.md into Chinese #118

Merged
merged 10 commits into from
Apr 15, 2019
64 changes: 32 additions & 32 deletions content/docs/forwarding-refs.md
Original file line number Diff line number Diff line change
@@ -1,76 +1,76 @@
---
id: forwarding-refs
title: Forwarding Refs
title: Refs 转发
permalink: docs/forwarding-refs.html
---

Ref forwarding is a technique for automatically passing a [ref](/docs/refs-and-the-dom.html) through a component to one of its children. This is typically not necessary for most components in the application. However, it can be useful for some kinds of components, especially in reusable component libraries. The most common scenarios are described below.
Ref 转发是一项将 [ref](/docs/refs-and-the-dom.html) 自动地通过组件传递到其一子组件的技巧。对于大多数应用中的组件来说,这通常不是必需的。但其对某些组件,尤其是可重用的组件库是很有用的。最常见的案例如下所述。

## Forwarding refs to DOM components {#forwarding-refs-to-dom-components}
## 转发 refs DOM 组件 {#forwarding-refs-to-dom-components}

Consider a `FancyButton` component that renders the native `button` DOM element:
考虑这个渲染原生 DOM 元素 `button` 的 `FancyButton` 组件:
`embed:forwarding-refs/fancy-button-simple.js`

React components hide their implementation details, including their rendered output. Other components using `FancyButton` **usually will not need to** [obtain a ref](/docs/refs-and-the-dom.html) to the inner `button` DOM element. This is good because it prevents components from relying on each other's DOM structure too much.
React 组件隐藏其实现细节,包括其渲染结果。其他使用 `FancyButton` 的组件**通常不需要**获取内部的 DOM 元素 `button` 的 [ref](/docs/refs-and-the-dom.html)。这很好,因为这防止组件过度依赖其他组件的 DOM 结构。

Although such encapsulation is desirable for application-level components like `FeedStory` or `Comment`, it can be inconvenient for highly reusable "leaf" components like `FancyButton` or `MyTextInput`. These components tend to be used throughout the application in a similar manner as a regular DOM `button` and `input`, and accessing their DOM nodes may be unavoidable for managing focus, selection, or animations.
虽然这种封装对类似 `FeedStory` `Comment` 这样的应用级组件是理想的,但其对 `FancyButton` `MyTextInput` 这样的高可复用“叶”组件来说可能是不方便的。这些组件倾向于在整个应用中以一种类似常规 DOM `button` `input` 的方式被使用,并且访问其 DOM 节点对管理焦点,选中或动画来说是不可避免的。

**Ref forwarding is an opt-in feature that lets some components take a `ref` they receive, and pass it further down (in other words, "forward" it) to a child.**
**Ref 转发是一个可选特性,其允许某些组件接收 `ref`,并将其向下传递(换句话说,“转发”它)给子组件。**

In the example below, `FancyButton` uses `React.forwardRef` to obtain the `ref` passed to it, and then forward it to the DOM `button` that it renders:
在下面的示例中,`FancyButton` 使用 `React.forwardRef` 来获取传递给它的 `ref`,然后转发到它渲染的 DOM `button`

`embed:forwarding-refs/fancy-button-simple-ref.js`

This way, components using `FancyButton` can get a ref to the underlying `button` DOM node and access it if necessary—just like if they used a DOM `button` directly.
这样,使用 `FancyButton` 的组件可以获取底层 DOM 节点 `button` 的 ref ,并在必要时访问,就像其直接使用 DOM `button` 一样。

Here is a step-by-step explanation of what happens in the above example:
以下是对上述示例发生情况的逐步解释:

1. We create a [React ref](/docs/refs-and-the-dom.html) by calling `React.createRef` and assign it to a `ref` variable.
1. We pass our `ref` down to `<FancyButton ref={ref}>` by specifying it as a JSX attribute.
1. React passes the `ref` to the `(props, ref) => ...` function inside `forwardRef` as a second argument.
1. We forward this `ref` argument down to `<button ref={ref}>` by specifying it as a JSX attribute.
1. When the ref is attached, `ref.current` will point to the `<button>` DOM node.
1. 我们通过调用 `React.createRef` 创建了一个 [React ref](/docs/refs-and-the-dom.html) 并将其赋值给 `ref` 变量。
1. 我们通过指定 `ref` 为 JSX 属性,将其向下传递给 `<FancyButton ref={ref}>`
1. React 传递 `ref` 给 `fowardRef` 内函数 `(props, ref) => ...`,作为其第二个参数。
1. 我们向下转发该 `ref` 参数到 `<button ref={ref}>`,将其指定为 JSX 属性。
1. ref 挂载完成,`ref.current` 将指向 `<button>` DOM 节点。

>Note
>注意
>
>The second `ref` argument only exists when you define a component with `React.forwardRef` call. Regular function or class components don't receive the `ref` argument, and ref is not available in props either.
>第二个参数 `ref` 只在使用 `React.forwardRef` 定义组件时存在。常规函数和 class 组件不接收 `ref` 参数,且 props 中也不存在 `ref`。
>
>Ref forwarding is not limited to DOM components. You can forward refs to class component instances, too.
>Ref 转发不仅限于 DOM 组件,你也可以转发 refs class 组件实例中。

## Note for component library maintainers {#note-for-component-library-maintainers}
## 组件库维护者的注意事项 {#note-for-component-library-maintainers}

**When you start using `forwardRef` in a component library, you should treat it as a breaking change and release a new major version of your library.** This is because your library likely has an observably different behavior (such as what refs get assigned to, and what types are exported), and this can break apps and other libraries that depend on the old behavior.
**当你开始在组件库中使用 `forwardRef` 时,你应当将其视为一个破坏性更改,并发布库的一个新的主版本。** 这是因为你的库可能会有明显不同的行为(例如 refs 被分配给了谁,以及导出了什么类型),并且这样可能会导致依赖旧行为的应用和其他库崩溃。

Conditionally applying `React.forwardRef` when it exists is also not recommended for the same reasons: it changes how your library behaves and can break your users' apps when they upgrade React itself.
出于同样的原因,当 `React.forwardRef` 存在时有条件地使用它也是不推荐的:它改变了你的库的行为,并在升级 React 自身时破环用户的应用。

## Forwarding refs in higher-order components {#forwarding-refs-in-higher-order-components}
## 在高阶组件中转发 refs {#forwarding-refs-in-higher-order-components}

This technique can also be particularly useful with [higher-order components](/docs/higher-order-components.html) (also known as HOCs). Let's start with an example HOC that logs component props to the console:
这个技巧对[高阶组件](/docs/higher-order-components.html)(也被称为 HOC)特别有用。让我们从一个输出组件 props 到控制台的 HOC 示例开始:
`embed:forwarding-refs/log-props-before.js`

The "logPropsHOC passes all `props` through to the component it wraps, so the rendered output will be the same. For example, we can use this HOC to log all props that get passed to our "fancy button" component:
logPropsHOC 透传(pass through)所有 `props` 到其包裹的组件,所以渲染结果将是相同的。例如:我们可以使用该 HOC 记录所有传递到 “fancy button” 组件的 props:
`embed:forwarding-refs/fancy-button.js`

There is one caveat to the above example: refs will not get passed through. That's because `ref` is not a prop. Like `key`, it's handled differently by React. If you add a ref to a HOC, the ref will refer to the outermost container component, not the wrapped component.
上面的示例有一点需要注意:refs 将不会透传下去。这是因为 `ref` 不是 prop 属性。就像 `key` 一样,其被 React 进行了特殊处理。如果你对 HOC 添加 ref,该 ref 将引用最外层的容器组件,而不是被包裹的组件。

This means that refs intended for our `FancyButton` component will actually be attached to the `LogProps` component:
这意味着用于我们 `FancyButton` 组件的 refs 实际上将被挂载到 `LogProps` 组件:
`embed:forwarding-refs/fancy-button-ref.js`

Fortunately, we can explicitly forward refs to the inner `FancyButton` component using the `React.forwardRef` API. `React.forwardRef` accepts a render function that receives `props` and `ref` parameters and returns a React node. For example:
幸运的是,我们可以使用 `React.forwardRef` API 明确地将 refs 转发到内部的 `FancyButton` 组件。`React.forwardRef` 接受一个渲染函数,其接收 `props` `ref` 参数并返回一个 React 节点。例如:
`embed:forwarding-refs/log-props-after.js`

## Displaying a custom name in DevTools {#displaying-a-custom-name-in-devtools}
## DevTools 中显示自定义名称 {#displaying-a-custom-name-in-devtools}

`React.forwardRef` accepts a render function. React DevTools uses this function to determine what to display for the ref forwarding component.
`React.forwardRef` 接受一个渲染函数。React DevTools 使用该函数来决定为 ref 转发组件显示的内容。

For example, the following component will appear as "*ForwardRef*" in the DevTools:
例如,以下组件将在 DevTools 中显示为 “*ForwardRef*”:

`embed:forwarding-refs/wrapped-component.js`

If you name the render function, DevTools will also include its name (e.g. "*ForwardRef(myFunction)*"):
如果你命名了渲染函数,DevTools 也将包含其名称(例如 “*ForwardRef(myFunction)*”):
QC-L marked this conversation as resolved.
Show resolved Hide resolved

`embed:forwarding-refs/wrapped-component-with-function-name.js`

You can even set the function's `displayName` property to include the component you're wrapping:
你甚至可以设置函数的 `displayName` 属性来包含被包裹组件的名称:

`embed:forwarding-refs/customized-display-name.js`
4 changes: 2 additions & 2 deletions examples/forwarding-refs/customized-display-name.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ function logProps(Component) {
return <LogProps {...props} forwardedRef={ref} />;
}

// Give this component a more helpful display name in DevTools.
// e.g. "ForwardRef(logProps(MyComponent))"
// DevTools 中为该组件提供一个更有用的显示名。
// 例如 “ForwardRef(logProps(MyComponent))
QC-L marked this conversation as resolved.
Show resolved Hide resolved
// highlight-range{1-2}
const name = Component.displayName || Component.name;
forwardRef.displayName = `logProps(${name})`;
Expand Down
8 changes: 4 additions & 4 deletions examples/forwarding-refs/fancy-button-ref.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import FancyButton from './FancyButton';
// highlight-next-line
const ref = React.createRef();

// The FancyButton component we imported is the LogProps HOC.
// Even though the rendered output will be the same,
// Our ref will point to LogProps instead of the inner FancyButton component!
// This means we can't call e.g. ref.current.focus()
// 我们导入的 FancyButton 组件是高阶组件(HOC)LogProps。
// 尽管渲染结果将是一样的,
// 但我们的 ref 将指向 LogProps 而不是内部的 FancyButton 组件!
// 这意味着我们不能调用例如 ref.current.focus() 这样的方法
// highlight-range{4}
<FancyButton
label="Click Me"
Expand Down
2 changes: 1 addition & 1 deletion examples/forwarding-refs/fancy-button-simple-ref.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ const FancyButton = React.forwardRef((props, ref) => (
</button>
));

// You can now get a ref directly to the DOM button:
// 你可以直接获取 DOM button 的 ref
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;
4 changes: 2 additions & 2 deletions examples/forwarding-refs/fancy-button.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class FancyButton extends React.Component {
// ...
}

// Rather than exporting FancyButton, we export LogProps.
// It will render a FancyButton though.
// 我们导出 LogProps,而不是 FancyButton
// 虽然它也会渲染一个 FancyButton
// highlight-next-line
export default logProps(FancyButton);
8 changes: 4 additions & 4 deletions examples/forwarding-refs/log-props-after.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ function logProps(Component) {
// highlight-next-line
const {forwardedRef, ...rest} = this.props;

// Assign the custom prop "forwardedRef" as a ref
// 将自定义的 prop 属性 “forwardedRef” 定义为 ref
// highlight-next-line
return <Component ref={forwardedRef} {...rest} />;
}
}

// Note the second param "ref" provided by React.forwardRef.
// We can pass it along to LogProps as a regular prop, e.g. "forwardedRef"
// And it can then be attached to the Component.
// 注意 React.forwardRef 回调的第二个参数 “ref”。
// 我们可以将其作为常规 prop 属性传递给 LogProps,例如 “forwardedRef
// 然后它就可以被挂载到被 LogPros 包裹的子组件上。
// highlight-range{1-3}
return React.forwardRef((props, ref) => {
return <LogProps {...props} forwardedRef={ref} />;
Expand Down