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/cloneElement into Chinese #1207

Merged
merged 15 commits into from
Jun 27, 2023
Merged
112 changes: 56 additions & 56 deletions src/content/reference/react/cloneElement.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ title: cloneElement

<Pitfall>

Using `cloneElement` is uncommon and can lead to fragile code. [See common alternatives.](#alternatives)
使用 `cloneElement` 并不常见,并且可能会导致代码变得脆弱。[查看常见的替代方案](#alternatives)

</Pitfall>

<Intro>

`cloneElement` lets you create a new React element using another element as a starting point.
`cloneElement` 允许你使用一个元素作为初始值创建一个新的 React 元素。

```js
const clonedElement = cloneElement(element, props, ...children)
Expand All @@ -22,11 +22,11 @@ const clonedElement = cloneElement(element, props, ...children)

---

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

### `cloneElement(element, props, ...children)` {/*cloneelement*/}

Call `cloneElement` to create a React element based on the `element`, but with different `props` and `children`:
调用 `cloneElement` 方法会基于 `element` 创建一个新的 React 元素,但新元素具有不同的 `props` `children`

```js
import { cloneElement } from 'react';
Expand All @@ -43,42 +43,42 @@ const clonedElement = cloneElement(
console.log(clonedElement); // <Row title="Cabbage">Goodbye</Row>
```

[See more examples below.](#usage)
[请参阅下面的更多示例](#usage)

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

* `element`: The `element` argument must be a valid React element. For example, it could be a JSX node like `<Something />`, the result of calling [`createElement`](/reference/react/createElement), or the result of another `cloneElement` call.
* `element``element` 参数必须是一个有效的 React 元素。例如,它可以是一个类似 `<Something />` 这样的 JSX 节点,也可以是 [`createElement`](/reference/react/createElement) 调用的结果,或者也可以是另一个 `cloneElement` 调用的结果。

* `props`: The `props` argument must either be an object or `null`. If you pass `null`, the cloned element will retain all of the original `element.props`. Otherwise, for every prop in the `props` object, the returned element will "prefer" the value from `props` over the value from `element.props`. The rest of the props will be filled from the original `element.props`. If you pass `props.key` or `props.ref`, they will replace the original ones.
* `props``props` 参数必须是一个对象或 `null`。如果传 `null`,克隆后的元素将保留所有原始的 `element.props`。否则,对于 `props` 对象中的每个 prop 属性,返回的元素将“优先”使用 `props` 中的值而不是 `element.props` 中的值。其余的 props 将从原始的 `element.props` 中填充。如果你传递 `props.key` 或者 `props.ref`,它们将替换原来的。

* **optional** `...children`: Zero or more child nodes. They can be any React nodes, including React elements, strings, numbers, [portals](/reference/react-dom/createPortal), empty nodes (`null`, `undefined`, `true`, and `false`), and arrays of React nodes. If you don't pass any `...children` arguments, the original `element.props.children` will be preserved.
* **可选** `...children`:零个或多个子节点。它们可以是任何 React 节点,包括 React 元素、字符串、数字、[portals](/reference/react-dom/createPortal)、空节点(`null``undefined``true` `false`),和 React 元素数组。如果你不传递任何 `...children` 参数,则原始的 `element.props.children` 将被保留。

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

`cloneElement` returns a React element object with a few properties:
`cloneElement` 返回一个具有一些属性的 React element 对象:

* `type`: Same as `element.type`.
* `props`: The result of shallowly merging `element.props` with the overriding `props` you have passed.
* `ref`: The original `element.ref`, unless it was overridden by `props.ref`.
* `key`: The original `element.key`, unless it was overridden by `props.key`.
* `type`:与 `element.type` 相同。
* `props`:将 `element.props` 与你传递的 `props` 浅合并的结果。
* `ref`:原始的 `element.ref`,除非它被 `props.ref` 覆盖。
* `key`:原始的 `element.key`,除非它被 `props.key` 覆盖。

Usually, you'll return the element from your component or make it a child of another element. Although you may read the element's properties, it's best to treat every element as opaque after it's created, and only render it.
通常,你将从组件返回该元素或使其成为另一个元素的子元素。尽管你可以读取元素的属性,但最好在创建每个元素后将其视为不透明的,并且仅渲染它。

#### Caveats {/*caveats*/}
#### 注意事项 {/*caveats*/}

* Cloning an element **does not modify the original element.**
* 克隆一个元素 **不会修改原始元素**。

* You should only **pass children as multiple arguments to `cloneElement` if they are all statically known,** like `cloneElement(element, null, child1, child2, child3)`. If your children are dynamic, pass the entire array as the third argument: `cloneElement(element, null, listItems)`. This ensures that React will [warn you about missing `key`s](/learn/rendering-lists#keeping-list-items-in-order-with-key) for any dynamic lists. For static lists this is not necessary because they never reorder.
* 如果已知 children 是静态的,则你应该 **将它们作为多个参数传递给 `cloneElement`**,例如 `cloneElement(element, null, child1, child2, child3)`。如果你的 children 是动态的,请将整个数组作为第三个参数传递:`cloneElement(element, null, listItems)`。这确保了 React 会对任何动态列表 [警告你缺少“key](/learn/rendering-lists#keeping-list-items-in-order-with-key),对于静态的列表,这是不必要的,因为它们不会重新排序。

* `cloneElement` makes it harder to trace the data flow, so **try the [alternatives](#alternatives) instead.**
* `cloneElement` 会使得跟踪数据流向变得更加困难,所以请 **尝试使用 [替代方案](#alternatives)**。

---

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

### Overriding props of an element {/*overriding-props-of-an-element*/}
### 覆盖元素的 props {/*overriding-props-of-an-element*/}

To override the props of some <CodeStep step={1}>React element</CodeStep>, pass it to `cloneElement` with the <CodeStep step={2}>props you want to override</CodeStep>:
要覆盖某些 <CodeStep step={1}>React element</CodeStep> 的 props,请将其与 <CodeStep step={2}>要覆盖的 props</CodeStep> 一起传递给 `cloneElement`:

```js [[1, 5, "<Row title=\\"Cabbage\\" />"], [2, 6, "{ isHighlighted: true }"], [3, 4, "clonedElement"]]
import { cloneElement } from 'react';
Expand All @@ -90,11 +90,11 @@ const clonedElement = cloneElement(
);
```

Here, the resulting <CodeStep step={3}>cloned element</CodeStep> will be `<Row title="Cabbage" isHighlighted={true} />`.
在这里,生成的 <CodeStep step={3}>克隆 element</CodeStep> 将为 `<Row title="Cabbage" isHighlighted={true} />`

**Let's walk through an example to see when it's useful.**
**让我们看一个示例,看看它什么时候有用**。

Imagine a `List` component that renders its [`children`](/learn/passing-props-to-a-component#passing-jsx-as-children) as a list of selectable rows with a "Next" button that changes which row is selected. The `List` component needs to render the selected `Row` differently, so it clones every `<Row>` child that it has received, and adds an extra `isHighlighted: true` or `isHighlighted: false` prop:
想象一个 `List` 组件将其 [`children`](/learn/passing-props-to-a-component#passing-jsx-as-children) 渲染为可选择行的列表,并带有可更改的“下一步”按钮选择了哪一行。`List` 组件需要以不同的方式渲染所选的 `Row`,因此它克隆它收到的每个 `<Row>` 子级,并添加额外的 `isHighlighted: true` `isHighlighted: false` 属性:

```js {6-8}
export default function List({ children }) {
Expand All @@ -108,7 +108,7 @@ export default function List({ children }) {
)}
```

Let's say the original JSX received by `List` looks like this:
假设 `List` 收到的原始 JSX 如下所示:

```js {2-4}
<List>
Expand All @@ -118,7 +118,7 @@ Let's say the original JSX received by `List` looks like this:
</List>
```

By cloning its children, the `List` can pass extra information to every `Row` inside. The result looks like this:
通过克隆其 children`List` 可以将额外的信息传递给内部的每个 `Row`。结果如下:

```js {4,8,12}
<List>
Expand All @@ -137,7 +137,7 @@ By cloning its children, the `List` can pass extra information to every `Row` in
</List>
```

Notice how pressing "Next" updates the state of the `List`, and highlights a different row:
注意点击“下一步”如何更新 `List` 的状态,并高亮显示不同的行:

<Sandpack>

Expand Down Expand Up @@ -178,7 +178,7 @@ export default function List({ children }) {
(i + 1) % Children.count(children)
);
}}>
Next
下一步
</button>
</div>
);
Expand Down Expand Up @@ -232,21 +232,21 @@ button {

</Sandpack>

To summarize, the `List` cloned the `<Row />` elements it received and added an extra prop to them.
总而言之,`List` 克隆了它接收的 `<Row />` 元素,并向它们添加额外的 props。

<Pitfall>

Cloning children makes it hard to tell how the data flows through your app. Try one of the [alternatives.](#alternatives)
克隆 children 使得你很难判断数据如何流经你的应用。尝试一种 [替代方案](#alternatives)

</Pitfall>

---

## Alternatives {/*alternatives*/}
## 替代方案 {/*alternatives*/}

### Passing data with a render prop {/*passing-data-with-a-render-prop*/}
### 通过 props 传递数据 {/*passing-data-with-a-render-prop*/}

Instead of using `cloneElement`, consider accepting a *render prop* like `renderItem`. Here, `List` receives `renderItem` as a prop. `List` calls `renderItem` for every item and passes `isHighlighted` as an argument:
接受类似 `renderItem` 这样的 *render prop* 代替 `cloneElement` 的用法。在这里,`List` 接收 `renderItem` 作为 props。`List` 为数组每一项调用 `renderItem`,并传递 `isHighlighted` 作为参数:

```js {1,7}
export default function List({ items, renderItem }) {
Expand All @@ -259,7 +259,7 @@ export default function List({ items, renderItem }) {
})}
```

The `renderItem` prop is called a "render prop" because it's a prop that specifies how to render something. For example, you can pass a `renderItem` implementation that renders a `<Row>` with the given `isHighlighted` value:
`renderItem` 属性称为“渲染属性”,因为它是决定如何渲染某些内容的属性。例如,你可以传递一个 `renderItem` 实现使用给定的 `isHighlighted` 值呈现 `<Row>`

```js {3,7}
<List
Expand All @@ -274,7 +274,7 @@ The `renderItem` prop is called a "render prop" because it's a prop that specifi
/>
```

The end result is the same as with `cloneElement`:
最终结果与 `cloneElement` 相同:

```js {4,8,12}
<List>
Expand All @@ -293,7 +293,7 @@ The end result is the same as with `cloneElement`:
</List>
```

However, you can clearly trace where the `isHighlighted` value is coming from.
但是你可以清楚地追踪 `isHighlighted` 的来源。

<Sandpack>

Expand Down Expand Up @@ -335,7 +335,7 @@ export default function List({ items, renderItem }) {
(i + 1) % items.length
);
}}>
Next
下一步
</button>
</div>
);
Expand Down Expand Up @@ -389,22 +389,22 @@ button {

</Sandpack>

This pattern is preferred to `cloneElement` because it is more explicit.
这种方案优于 `cloneElement`,因为它更加清晰。

---

### Passing data through context {/*passing-data-through-context*/}
### 通过 context 传递数据 {/*passing-data-through-context*/}

Another alternative to `cloneElement` is to [pass data through context.](/learn/passing-data-deeply-with-context)
`cloneElement` 的另一种替代方法是 [通过 context 传递数据](/learn/passing-data-deeply-with-context)


For example, you can call [`createContext`](/reference/react/createContext) to define a `HighlightContext`:
例如,你可以调用 [`createContext`](/reference/react/createContext) 来定义一个 `HighlightContext`

```js
export const HighlightContext = createContext(false);
```

Your `List` component can wrap every item it renders into a `HighlightContext` provider:
`List` 组件可以将其呈现的每个 item 传递到 `HighlightContext` provider 中:

```js {8,10}
export default function List({ items, renderItem }) {
Expand All @@ -421,15 +421,15 @@ export default function List({ items, renderItem }) {
})}
```

With this approach, `Row` does not need to receive an `isHighlighted` prop at all. Instead, it reads the context:
通过这种方法,`Row` 不需要接收 `isHighlighted`属性,因为它可以从 context 中读取:

```js Row.js {2}
export default function Row({ title }) {
const isHighlighted = useContext(HighlightContext);
// ...
```

This allows the calling component to not know or worry about passing `isHighlighted` to `<Row>`:
这允许调用组件时无需关心是否将 `isHighlighted` 传递给了 `<Row>`

```js {4}
<List
Expand All @@ -440,7 +440,7 @@ This allows the calling component to not know or worry about passing `isHighligh
/>
```

Instead, `List` and `Row` coordinate the highlighting logic through context.
相反,`List` `Row` 通过上下文协调突出显示逻辑。

<Sandpack>

Expand Down Expand Up @@ -486,7 +486,7 @@ export default function List({ items, renderItem }) {
(i + 1) % items.length
);
}}>
Next
下一步
</button>
</div>
);
Expand Down Expand Up @@ -550,13 +550,13 @@ button {

</Sandpack>

[Learn more about passing data through context.](/reference/react/useContext#passing-data-deeply-into-the-tree)
[了解有关通过 context 传递数据的更多信息](/reference/react/useContext#passing-data-deeply-into-the-tree)

---

### Extracting logic into a custom Hook {/*extracting-logic-into-a-custom-hook*/}
### 将逻辑提取到自定义 Hook {/*extracting-logic-into-a-custom-hook*/}

Another approach you can try is to extract the "non-visual" logic into your own Hook, and use the information returned by your Hook to decide what to render. For example, you could write a `useList` custom Hook like this:
你可以尝试的另一种方法是将“非视觉”部分的逻辑提取到你的自定义 Hook 中,并使用 Hook 的返回值来决定渲染什么。例如,你可以编写一个 `useList` 自定义 Hook,如下所示:

```js
import { useState } from 'react';
Expand All @@ -575,7 +575,7 @@ export default function useList(items) {
}
```

Then you could use it like this:
然后你可以像这样使用它:

```js {2,9,13}
export default function App() {
Expand All @@ -591,14 +591,14 @@ export default function App() {
)}
<hr />
<button onClick={onNext}>
Next
下一步
</button>
</div>
);
}
```

The data flow is explicit, but the state is inside the `useList` custom Hook that you can use from any component:
数据流是显式的,但状态位于 `useList` 自定义 Hook 内,你可以在任意一个组件内使用它:

<Sandpack>

Expand All @@ -620,7 +620,7 @@ export default function App() {
)}
<hr />
<button onClick={onNext}>
Next
下一步
</button>
</div>
);
Expand Down Expand Up @@ -691,4 +691,4 @@ button {

</Sandpack>

This approach is particularly useful if you want to reuse this logic between different components.
如果你想在不同组件之间复用此逻辑,则这个方案十分有用。