Files
rikako-note/react/react.md
2023-02-13 13:34:21 +08:00

192 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# React
## 概览
React是一个声明式用于构建用户界面的JavaScript库。React可以将一些简短、独立的代码片段组合成复杂的ui界面**独立的代码片段在React中被称之为组件**。
## React.Component组件
```js
class ShoppingList extends React.Component {
render() {
return (
<div className="shopping-list">
<h1>Shopping List for {this.props.name}</h1>
<ul>
<li>Instagram</li>
<li>WhatsApp</li>
<li>Oculus</li>
</ul>
</div>
);
}
}
// 用法示例: <ShoppingList name="Mark" />
```
可以通过组件来告诉React需要在屏幕上显示的内容当数据发生改变时**React会高效的更新内容并重新渲染组件**。
以上ShoppingList声明了一个React组件类型。React组件类型会接受一些组件参数该参数称之为`props`组件还会通过render方法返回显示在屏幕上的视图层次结构。
render方法的返回值将会描述希望在屏幕上看到的内容。render返回值是一个React元素是对渲染元素的轻量级描述。`jsx`语法支持更简单的书写这些结构,语法\</div\>会被编译为如下内容:
```js
return React.createElement('div', {className: 'shopping-list'},
React.createElement('h1', /* ... h1 children ... */),
React.createElement('ul', /* ... ul children ... */)
);
```
在jsx中可以在html元素中使用js表达式只需要用大括号将js表达式括起来。
```js
<h1>Shopping List for {this.props.name}</h1>
```
上述示例中的ShoppingList只渲染了一些内置的DOM组件`div`,`li`但是也可以组合和渲染自定义的React组件。例如可以通过`<ShoppingList/>`来表示整个购物清单组件。
> 每个组件都是封装好的,并可以单独运行,如此可以通过组合组件来构建复杂代码
## 组件响应事件及状态
### 事件处理函数
如果想要为组件指定事件处理函数,可以通过如下方式:
```js
class Square extends React.Component {
render() {
return (
<button className="square" onClick={function() { alert('click'); }}>
{this.props.value}
</button>
);
}
}
```
### 组件状态
可以通过在组件构造函数中初始化`this.state`属性来存储组件状态this.state应被视作组件的私有属性。
示例如下:
```js
class Square extends React.Component {
constructor(props) {
super(props);
this.state = {
value: null,
};
}
render() {
return (
<button className="square" onClick={() => alert('click')}>
{this.props.value}
</button>
);
}
}
```
可以通过如下代码来修改和渲染React组件中的state属性
```js
class Square extends React.Component {
constructor(props) {
super(props);
this.state = {
value: null,
};
}
render() {
return (
<button
className="square"
onClick={() => this.setState({value: 'X'})}
>
{this.state.value}
</button>
);
}
}
```
> ### setState
> 每次在组件内调用setState方法时React都会自动更新其子组件。
### 组件状态提升
如果需要同时获取多个子组件的数据或者多个组件之间需要通信此时可以将子组件的state数据提升至父组件中进行存储。
父子组件之间传递数据和处理函数的示例如下:
```js
// parent component,
// pass `value`,`onclick` props to child component
class Board extends React.Component {
constructor(props) {
super(props);
this.state = {
squares: Array(9).fill(null),
};
}
handleClick(i) {
const squares = this.state.squares.slice();
squares[i] = 'X';
this.setState({squares: squares});
}
renderSquare(i) {
return (
<Square
value={this.state.squares[i]}
onClick={() => this.handleClick(i)}
/>
);
}
render() {
const status = 'Next player: X';
return (
<div>
<div className="status">{status}</div>
<div className="board-row">
{this.renderSquare(0)}
{this.renderSquare(1)}
{this.renderSquare(2)}
</div>
<div className="board-row">
{this.renderSquare(3)}
{this.renderSquare(4)}
{this.renderSquare(5)}
</div>
<div className="board-row">
{this.renderSquare(6)}
{this.renderSquare(7)}
{this.renderSquare(8)}
</div>
</div>
);
}
}
// child component
class Square extends React.Component {
render() {
return (
<button
className="square"
onClick={() => this.props.onClick()}
>
{this.props.value}
</button>
);
}
}
```
### React不可变性
相比于直接修改原有数据的属性,直接用新对象替换旧的数据对象是更推荐的做法,其有如下优点:
- 如果需要查看属性的历史值或实现撤回功能那么不可变数据将会令实现相当简单只要存储历史state对象就可以
- 如果使用不可变对象,查看数据是否更改会容易很多,只需将旧对象地址和新对象地址进行比较即可,无需遍历对象结构并比较属性值
- 不可变对象可以轻易的发现数据对象是否发生改变从而确定React是否应该重新渲染
## 函数组件
如果组件中并不包含state状态且组件只包含render一个方法可以通过函数来实现其组件而无需继承React.Component类。
通过函数组件替换React.Component组件的示例如下
```js
function Square(props) {
return (
<button className="square" onClick={props.onClick}>
{props.value}
</button>
);
}
```
## React list
在React中使用列表时需要为列表项指定一个key以区分该列表项和其他兄弟列表项。
`key`是React中一个特殊的保留属性当React元素被创建时React会获取key属性并且将其存储到返回的元素中。元素的`key`属性并无法通过`this.props.key`形式来获取React会通过`key`自动判断哪些组件需要被更新,但是组件无法访问它的`key`
> 组件的key并不需要在全局保证唯一只需要在当前同一级元素之中key保持唯一即可