React 笔记—核心概念

本文基于官方 v18.1.0 文档。

Introducing JSX

Why JSX?

React embraces the fact that rendering logic is inherently coupled with other UI logic:
how events are handled, how the state changes over time, and how the data is prepared for display.

Instead of artificially separating technologies by putting markup and logic in separate files,
React separates concerns with loosely coupled units called “components” that contain both.

这是当初 React 最吸引我的地方,不执著于将 UI 和逻辑分开。MVC 大行其道几十年后,Android 跟 iOS 也都在尝试返濮了。
在我实际工作经验中,进行视图子类化定制的出发点往往就是为了将 UI 和其逻辑写在一起。这个需求越靠近业务层就越强烈。

Embedding Expressions in JSX

We split JSX over multiple lines for readability. While it isn’t required, when doing this,
we also recommend wrapping it in parentheses to avoid the pitfalls of automatic semicolon insertion.

Specifying Attributes with JSX

Since JSX is closer to JavaScript than to HTML, React DOM uses camelCase property naming convention instead of HTML attribute names.

For example, class becomes className in JSX, and tabindex becomes tabIndex.

JSX Prevents Injection Attacks

Everything is converted to a string before being rendered. This helps prevent XSS (cross-site-scripting) attacks.

Rendering Elements

Elements are the smallest building blocks of React apps.

Unlike browser DOM elements, React elements are plain objects, and are cheap to create.

React Only Updates What’s Necessary

React DOM compares the element and its children to the previous one, and only applies the DOM updates necessary to bring the DOM to the desired state.

Even though we create an element describing the whole UI tree on every tick, only the text node whose contents have changed gets updated by React DOM.

Components and Props

Rendering a Component

Always start component names with a capital letter.
React treats components starting with lowercase letters as DOM tags.

Props are Read-Only

functions are called “pure” because they do not attempt to change their inputs, and always return the same result for the same inputs.

All React components must act like pure functions with respect to their props.

act like, 说的是组件看起来像纯函数——从 props 角度上讲,而不是真正意义上的纯函数。只是强调 props 的不可变性。

State and Lifecycle

Adding Lifecycle Methods to a Class

The componentDidMount() method runs after the component output has been rendered to the DOM.

Using State Correctly

State Updates May Be Asynchronous

Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.

1
2
3
4
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));

Handling Events

you cannot return false to prevent default behavior in React. You must call preventDefault explicitly.

e is a synthetic event.

In JavaScript, class methods are not bound by default. Understanding JavaScript Bind ()

If calling bind annoys you, there are two ways you can get around this.

  • public class fields syntax
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class LoggingButton extends React.Component {
// This syntax ensures `this` is bound within handleClick.
// Warning: this is *experimental* syntax.
handleClick = () => {
console.log('this is:', this);
}

render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
);
}
}
  • arrow function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}

render() {
// This syntax ensures `this` is bound within handleClick
return (
<button onClick={() => this.handleClick()}>
Click me
</button>
);
}
}

The problem with this syntax is that a different callback is created each time the LoggingButton renders.

Conditional Rendering

Preventing Component from Rendering

In rare cases you might want a component to hide itself even though it was rendered by another component.
To do this return null instead of its render output.

Returning null from a component’s render method does not affect the firing of the component’s lifecycle methods.
For instance componentDidUpdate will still be called.

Lists and Keys

Keys

We don’t recommend using indexes for keys if the order of items may change.
This can negatively impact performance and may cause issues with component state.

If you choose not to assign an explicit key to list items then React will default to using indexes as keys.

Forms

Controlled Components

In HTML, form elements such as <input>, <textarea>, and <select> typically maintain their own state and update it based on user input.
In React, mutable state is typically kept in the state property of components, and only updated with setState().

We can combine the two by making the React state be the “single source of truth”.
Then the React component that renders a form also controls what happens in that form on subsequent user input.
An input form element whose value is controlled by React in this way is called a “controlled component”.

受控组件。简单说就是表单类 HTML 元素的 value 显示被 React 组件接管、控制了。

The textarea Tag

In HTML, a <textarea> element defines its text by its children:

1
2
3
<textarea>
Hello there, this is some text in a text area
</textarea>

In React, a <textarea> uses a value attribute instead.

The select Tag

React, instead of using this selected attribute, uses a value attribute on the root select tag.

You can pass an array into the value attribute, allowing you to select multiple options in a select tag.

The file input Tag

Because its value is read-only, it is an uncontrolled component in React.

Handling Multiple Inputs

Note how we used the ES6 computed property name syntax to update the state key corresponding to the given input name:

1
2
3
this.setState({
[name]: value
});

Computed property name: 计算属性名。把方括号内的表达式所表示的字符串值作为属性名。

Lifting State Up

Lifting State Up

In React, sharing state is accomplished by moving it up to the closest common ancestor of the components that need it. This is called “lifting state up”.

Composition vs Inheritance

Containment

Some components don’t know their children ahead of time. This is especially common for components like Sidebar or Dialog that represent generic “boxes”.

We recommend that such components use the special children prop to pass children elements directly into their output.

While this is less common, sometimes you might need multiple “holes” in a component. In such cases you may come up with your own convention instead of using children:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function SplitPane(props) {
return (
<div className="SplitPane">
<div className="SplitPane-left">
{props.left}
</div>
<div className="SplitPane-right">
{props.right}
</div>
</div>
);
}

function App() {
return (
<SplitPane
left={
<Contacts />
}
right={
<Chat />
} />
);
}

So What About Inheritance?

Remember that components may accept arbitrary props, including primitive values, React elements, or functions.

Thinking in React

Use the same techniques for deciding if you should create a new function or object. One such technique is the single responsibility principle, that is, a component should ideally only do one thing. If it ends up growing, it should be decomposed into smaller subcomponents.

评论