Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
134 changes: 124 additions & 10 deletions src/content/reference/react-dom/components/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,23 +162,137 @@ React 支持所有浏览器内置的组件,包括:

### 自定义 HTML 元素 {/*custom-html-elements*/}

如果你渲染一个带有连字符的标签,如 `<my-element>`,React 会认为你想要渲染一个 [自定义 HTML 元素](https://developer.mozilla.org/zh-CN/docs/Web/Web_Components/Using_custom_elements)。在 React 中,渲染自定义元素与渲染内置的浏览器标签有所不同:

- 所有自定义元素的 props 都将被序列化为字符串,并且总是使用属性(attribute)进行设置。
- 自定义元素接受 `class` 而不是 `className`,接受 `for` 而不是 `htmlFor`。
如果你渲染一个带有连字符的标签,如 `<my-element>`,React 会认为你想要渲染一个 [自定义 HTML 元素](https://developer.mozilla.org/zh-CN/docs/Web/Web_Components/Using_custom_elements)。

如果你使用 [`is`](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Global_attributes/is) 属性渲染一个内置的浏览器 HTML 元素,它也会被视为自定义元素。

<Note>
#### Setting values on custom elements {/*attributes-vs-properties*/}

Custom elements have two methods of passing data into them:

1) Attributes: Which are displayed in markup and can only be set to string values
2) Properties: Which are not displayed in markup and can be set to arbitrary JavaScript values

By default, React will pass values bound in JSX as attributes:

```jsx
<my-element value="Hello, world!"></my-element>
```

Non-string JavaScript values passed to custom elements will be serialized by default:

```jsx
// Will be passed as `"1,2,3"` as the output of `[1,2,3].toString()`
<my-element value={[1,2,3]}></my-element>
```

React will, however, recognize an custom element's property as one that it may pass arbitrary values to if the property name shows up on the class during construction:

<Sandpack>

```js src/index.js hidden
import {MyElement} from './MyElement.js';
import { createRoot } from 'react-dom/client';
import {App} from "./App.js";

customElements.define('my-element', MyElement);

const root = createRoot(document.getElementById('root'))
root.render(<App />);
```

```js src/MyElement.js active
export class MyElement extends HTMLElement {
constructor() {
super();
// The value here will be overwritten by React
// when initialized as an element
this.value = undefined;
}

connectedCallback() {
this.innerHTML = this.value.join(", ");
}
}
```

[未来的 React 版本将提供更全面的自定义元素支持](https://github.com/facebook/react/issues/11347#issuecomment-1122275286)。
```js src/App.js
export function App() {
return <my-element value={[1,2,3]}></my-element>
}
```

你可以通过将 React 包升级到最新的实验性版本来尝试:
</Sandpack>

#### Listening for events on custom elements {/*custom-element-events*/}

A common pattern when using custom elements is that they may dispatch [`CustomEvent`s](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent) rather than accept a function to call when an event occur. You can listen for these events using an `on` prefix when binding to the event via JSX.

<Sandpack>

```js src/index.js hidden
import {MyElement} from './MyElement.js';
import { createRoot } from 'react-dom/client';
import {App} from "./App.js";

customElements.define('my-element', MyElement);

const root = createRoot(document.getElementById('root'))
root.render(<App />);
```

```javascript src/MyElement.js
export class MyElement extends HTMLElement {
constructor() {
super();
this.test = undefined;
this.emitEvent = this._emitEvent.bind(this);
}

_emitEvent() {
const event = new CustomEvent('speak', {
detail: {
message: 'Hello, world!',
},
});
this.dispatchEvent(event);
}

connectedCallback() {
this.el = document.createElement('button');
this.el.innerText = 'Say hi';
this.el.addEventListener('click', this.emitEvent);
this.appendChild(this.el);
}

disconnectedCallback() {
this.el.removeEventListener('click', this.emitEvent);
}
}
```

```jsx src/App.js active
export function App() {
return (
<my-element
onspeak={e => console.log(e.detail.message)}
></my-element>
)
}
```

</Sandpack>

<Note>

- `react@experimental`
- `react-dom@experimental`
Events are case-sensitive and support dashes (`-`). Preserve the casing of the event and include all dashes when listening for custom element's events:

实验性版本的 React 可能包含一些错误,因此不要在生产环境中使用。
```jsx
// Listens for `say-hi` events
<my-element onsay-hi={console.log}></my-element>
// Listens for `sayHi` events
<my-element onsayHi={console.log}></my-element>
```

</Note>
---
Expand Down
12 changes: 6 additions & 6 deletions src/content/reference/react/Activity.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ While hidden, children still re-render in response to new props, albeit at a low

When the boundary becomes <CodeStep step={3}>visible</CodeStep> again, React will reveal the children with their previous state restored, and re-create their Effects.

In this way, Activity can thought of as a mechanism for rendering "background activity". Rather than completely discarding content that's likely to become visible again, you can use Activity to maintain and restore that content's UI and internal state, while ensuring hidden content has no unwanted side effects.
In this way, Activity can be thought of as a mechanism for rendering "background activity". Rather than completely discarding content that's likely to become visible again, you can use Activity to maintain and restore that content's UI and internal state, while ensuring that your hidden content has no unwanted side effects.

[See more examples below.](#usage)

Expand All @@ -62,15 +62,15 @@ In this way, Activity can thought of as a mechanism for rendering "background ac

#### Caveats {/*caveats*/}

- When used with `<ViewTransition>`, hidden activities that reveal in a transition will activate an "enter" animation. Visible Activities hidden in a transition will activate an "exit" animation.
- If an Activity is rendered inside of a [ViewTransition](/reference/react/ViewTransition), and it becomes visible as a result of an update caused by [startTransition](/reference/react/startTransition), it will activate the ViewTransition's `enter` animation. If it becomes hidden, it will activate its `exit` animation.

---

## Usage {/*usage*/}

### Restoring the state of hidden components {/*restoring-the-state-of-hidden-components*/}

Typically in React, when you want to conditionally show or hide a component, you mount and unmount it:
In React, when you want to conditionally show or hide a component, you typically mount or unmount it based on that condition:

```jsx
{isShowingSidebar && (
Expand All @@ -88,11 +88,11 @@ When you hide a component using an Activity boundary instead, React will "save"
</Activity>
```

This makes it possible to restore components to their previous state.
This makes it possible to hide and then later restore components in the state they were previously in.

The following example has a sidebar with an expandable section – you can press "Overview" to reveal the three subitems below it. The main app area also has a button that hides and shows the sidebar.
The following example has a sidebar with an expandable section. You can press "Overview" to reveal the three subitems below it. The main app area also has a button that hides and shows the sidebar.

Try expanding the Overview section, then toggling the sidebar closed and open:
Try expanding the Overview section, and then toggling the sidebar closed then open:

<Sandpack>

Expand Down