React 备忘清单
===

适合初学者的综合 React 备忘清单。


入门
----

### 介绍

React 是一个用于构建用户界面的 JavaScript 库。

- [React 官方文档](https://reactjs.org/) _(reactjs.org)_

```js
import React from 'react'
import {createRoot} from 'react-dom/client'
import App from './App'
```

-----

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

### 导入多个导出

```jsx
import React, {Component} from 'react'
import ReactDOM from 'react-dom'
```

-----

```jsx
export class Hello extends Component {
  ...
}
```

使用 `export` 或者 `export default` 导出 `Hello` 组件

```jsx
import { Hello } from './hello.js';

const Example = <Hello />;
```

使用 `import` 导入 `Hello` 组件,在示例中使用。


### React 组件中的 CSS

```jsx
import React from "react";
import "./Student.css";

export const Student = (
  <div className="Student"></div>
);
```

注意:类属性 `className`

```jsx
const divStyle = {
  backgroundImage: 'url(' + imgUrl + ')',
};
export const Student = (
  <div style={divStyle}></div>
);
```


### 属性

```jsx
<Student name="Julie" age={23}
  pro={true} />
```

函数组件 `Student` 中访问属性

```jsx
function Student(props) {
  return <h1>Hello, {props.name}</h1>;
}
```

Class 组件 `Student` 中访问属性

```jsx
class Student extends React.Component {
  render() {
    return (
      <h1>Hello, {this.props.name}</h1>
    );
  }
}
```

`class` 组件使用 `this.props` 访问传递给组件的属性。


### Children
<!--rehype:wrap-class=row-span-2-->

```jsx
function Example() {
  return (
    <AlertBox>
      <h1>您有待处理的通知</h1>
    </AlertBox>
  )
}
```

函数 `AlertBox` 组件

```jsx
function AlertBox(props) {
  return (
    <div className="alert-box">
      {props.children}
    </div>
  );
}
```

----

```jsx
{props.children}
```

Class `AlertBox` 组件,与函数组件 `AlertBox` 组件相同

```jsx
class AlertBox extends React.Component {
  render () {
    return (
      <div className="alert-box">
        {this.props.children}
      </div>
    );
  }
}
```

----

```jsx
{this.props.children}
```

`children` 作为子组件的的属性传递。

### State
<!--rehype:wrap-class=row-span-3-->

函数中的 State,Hook 是 React 16.8 的新增特性

```jsx
import { useState } from 'react';

function Student() {
  // 声明一个叫 "count" 的 state 变量
  const [count, setCount] = useState(0);
  const click = () => setCount(count + 1);

  return (
    <div>
      <p>您点击了 {count} 次</p>
      <button onClick={click}>
        点击我
      </button>
    </div>
  );
}
```

使用 `setState` 更新状态,下面是函数组件读取状态

```jsx
<p>您点击了 {count} 次</p>
```

#### Class 中的 State

```jsx
import React from 'react';

class Student extends React.Component {
  constructor(props) {
    super(props);
    this.state = {count: 1};
  }
  click() {
    const count = this.state.count;
    this.setState({ count: count + 1})
  }
  render() {
    return (
      <div>
        <button onClick={this.click}>
          点击我
        </button>
        <p>您点击了{this.state.count}次</p>
      </div>
    );
  }
}
```

使用 `setState` 更新状态,`class` 组件中不能使用 <yel>~~hooks~~</yel>。下面是 `class` 组件读取状态

```jsx
<p>您点击了{this.state.count}次</p>
```

### 循环

```jsx
const elm = ['one', 'two', 'three'];
function Student() {
  return (
    <ul>
      {elm.map((value, index) => (
        <li key={index}>{value}</li>
      ))}
    </ul>
  );
}
```

`key` 值在兄弟节点之间必须唯一

### 事件监听

```jsx
export default function Hello() {
  function handleClick(event) {
    event.preventDefault();
    alert("Hello World");
  }

  return (
    <a href="/" onClick={handleClick}>
      Say Hi
    </a>
  );
}
```

### 函数注入

```jsx
function addNumbers(x1, x2) {
  return x1 + x2;
}

const element = (
  <div>{addNumbers(2, 5)}</div>
)
```

### 嵌套

```jsx
import { useState } from 'react'
import Avatar from './Avatar';
import Profile from './Profile';

function Student() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <Avatar src={count} />
      <Profile username={count} />
    </div>
  );
}
```

### Fragment

```jsx
import { Fragment } from 'react'
import Avatar from './Avatar';
import Profile from './Profile';

const Student = () => (
  <Fragment>
    <Avatar src="./demo.jpg" />
    <Profile username="name" />
  </Fragment>
)
```

从 @v16.2.0 开始,`Fragment` 可用于返回多个子节点,而无需向 DOM 添加额外的包装节点。

### Portals

React 并*没有*创建一个新的 `div`。它只是把子元素渲染到 `domNode` 中。`domNode` 是一个可以在任何位置的有效 DOM 节点。

```jsx
render() {
  return ReactDOM.createPortal(
    this.props.children,
    domNode
  );
}
```

提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案

默认值
---

### Class 组件默认 props
<!--rehype:wrap-class=row-span-2-->

```jsx
class CustomButton extends React.Component {
  // ...
}
CustomButton.defaultProps = {
  color: 'blue'
};
```

#### 使用

```jsx
<CustomButton /> ;
```

不传值 `props.color` 将自动设置为 `blue`

### Class 组件默认 state
<!--rehype:wrap-class=row-span-2-->

```jsx
class Hello extends Component {
  constructor (props) {
    super(props)
    this.state = { visible: true }
  }
}
```

在构造 `constructor()`中设置默认状态。

```jsx
class Hello extends Component {
  state = { visible: true }
}
```

### 函数组件默认 props

```jsx
function CustomButton(props) {
  const { color = 'blue' } = props;
  return <div>{color}</div>
}
```

### 函数组件默认 state

```jsx
function CustomButton() {
  const [color, setColor]=useState('blue')
  return <div>{color}</div>
}
```

JSX
---

### 介绍
<!--rehype:wrap-class=row-span-2-->

`JSX` 仅仅只是 `React.createElement(component, props, ...children)` 函数的语法糖

```jsx
<MyButton color="blue" shadowSize={2}>
  点击我
</MyButton>
```

会编译为

```js
React.createElement(
  MyButton,
  {color: 'blue', shadowSize: 2},
  '点击我'
);
```

没有子节点

```jsx
<div className="sidebar" />
```

会编译为

```js
React.createElement(
  'div',
  {className: 'sidebar'}
)
```

### JSX 点语法

```jsx
const Menu = ({ children }) => (
  <div className="menu">{children}<div>
);

Menu.Item = ({ children }) => (
  <div>{children}<div>
);

<Menu>
  <Menu.Item>菜单一</Menu.Item>
  <Menu.Item>菜单二</Menu.Item>
<Menu>
```

### JSX Element

```jsx
let element = <h1>Hello, world!</h1>;
let emptyHeading = <h1 />;

const root = ReactDOM.createRoot(
  document.getElementById('root')
);
const element = <h1>Hello, world</h1>;
root.render(element);
```

参考:[渲染元素](https://reactjs.org/docs/rendering-elements.html)

### JSX 属性

```jsx
const element = (
  <img src={user.avatarUrl} />
);

const element = (
  <button className="btn">
    点击我
  </button>
);
```

注意:类属性 `className`

### JSX 表达式

```jsx
let name = 'Josh Perez';
let element = <h1>Hello, {name}</h1>;

function fullName(firstName, lastName) {
  return firstName + ' ' + lastName;
}
let element = (
  <h1>
    Hello, {fullName('Julie', 'Johnson')}
  </h1>
);
```

### JSX style

```jsx
const divStyle = {
  color: 'blue',
  backgroundImage: 'url(' + imgUrl + ')',
};
function MyComponent() {
  return <div style={divStyle}>组件</div>;
}
```

### JSX dangerouslySetInnerHTML

```jsx
const markup = {__html: '我 &middot; 你' };

const MyComponent = () => (
  <div dangerouslySetInnerHTML={markup} />
);
```

`dangerouslySetInnerHTML` 是 React 为浏览器 DOM 提供 `innerHTML` 的替换方案。

### JSX htmlFor

```jsx
const MyComponent = () => (
  <div>
    <input type="radio" id="ab" name="v">
    <label for="ab">HTML</label>
  </div>
);
```

`for` 在 `JS` 中是保留字,JSX 元素使用了 `htmlFor` 代替

### JSX defaultValue

非受控组件的属性,设置组件第一次挂载时的 `value`

```jsx
<textarea defaultValue="Hello" />
```

`<input>`、`<select>` 和 `<textarea>` 支持 value 属性

### JSX defaultChecked

非受控组件的属性,设置组件是否被选中

```jsx
<input type="radio" defaultChecked />
```

类型为 `checkbox` 或 `radio` 时,组件支持 checked 属性

### JSX className

属性用于指定 `CSS` 的 `class`

```jsx
<div className="warp">...</div>
```

React 中使用 [Web Components](https://developer.mozilla.org/zh-CN/docs/Web/Web_Components) 使用 `class` 属性代替

### JSX 条件渲染
<!--rehype:wrap-class=row-span-2-->

```jsx
import React from "react";

function formatName(user) {
  return user.firstName 
    + ' ' 
    + user.lastName;
}

export function Greeting(user) {
  if (user) {
    return (
      <h1>你好, {formatName(user)}!</h1>
    );
  }
  return (
    <h1>你好, 先生。</h1>
  );
}
```

注意:组件必须总是返回一些东西。

#### 使用

```jsx
<Greeting firstName="三" lastName="张" />
```

### JSX 三目运算符 / 与运算符 &&

```jsx
export default function Weather(props) {
  const isLoggedIn = props.isLoggedIn;
  return (
    <div>
      <b>{isLoggedIn ? '已' : '未'}</b>登录。
    </div>
  );
}
```

----

```js
{isShow && <div>内容</div>}
```

### JSX 组件

```jsx
<Dropdown>
  下拉列表
  <Menu>
    <Menu.Item>菜单一</Menu.Item>
    <Menu.Item>菜单二</Menu.Item>
    <Menu.Item>菜单三</Menu.Item>
  </Menu>
</Dropdown>
```

组件名称以大驼峰式命名。

### JSX 元素变量

```jsx
function Greeting(props) {
  let button;
  if (props.isLoggedIn) {
    button = <UserGreeting />;
  } else {
    button = <GuestGreeting />;
  }
  return <div>{button}</div>;
}
```

### JSX 注释

```jsx
function Student() {
  const [count, setCount] = useState(0);
  return (
    <Fragment>
      {/* 这里写注释 */}
    </Fragment>
  );
}
```

组件
----

### 函数组件
<!--rehype:wrap-class=row-span-2-->

```jsx
import React from 'react';

const UserName = () => <h1>Kenny</h1>;

export default function UserProfile() {
  return (
    <div className="UserProfile">
      <div>Hello</div>  
      <UserName />
    </div>
  );
}
```

注意:每个组件都需要一个根元素,[更多说明](https://reactjs.org/docs/components-and-props.html)。

### Class 组件

```jsx
class Welcome extends React.Component {
  render() {
    return <h1>{this.props.name}</h1>;
  }
}
```

### Class 组件 API
<!--rehype:wrap-class=row-span-2-->

#### 额外的 API

:- | -
:- | -
`this.forceUpdate()` | 强制重新渲染
`this.setState({ ... })` | 更新状态
`this.setState(state =>{ ... })` | 更新状态

#### 属性

:- | -
:- | -
`defaultProps` | 默认 props
`displayName` | 显示组件名称(用于调试)

#### 实例属性

:- | -
:- | -
`this.props` | 组件接受参数
`this.state` | 组件内状态


### Pure 组件

```jsx
import React, {PureComponent} from 'react'

class MessageBox extends PureComponent {
  ···
}
```
### 嵌入内部组件

```jsx
import React from 'react';
import UserAvatar from "./UserAvatar";

export default function UserProfile() {
  return (
    <div className="UserProfile">
      <UserAvatar />
      <UserAvatar />
    </div>
  );
}
```

注意:假设 `UserAvatar` 在 `UserAvatar.js` 中声明。

### 嵌入外部组件

```jsx
import React from 'react';
import CompName from 'component-name';

export default function UserProfile() {
  return (
    <div className="UserProfile">
      <CompName />
    </div>
  );
}
```

注意:外部组件在 [npmjs.com](https://www.npmjs.com) 上找到,需要先安装导入。

### 高阶组件

```jsx
import React, { Component } from 'react';
// 高阶组件 with
const with = data => WrappedComponent => {
  return class extends Component {
    constructor(props) {
      super(props);
    }
    render() {
      return (
        <WrappedComponent data={data} />
      )
    }
  }
}
```

使用高阶组件

```jsx
const LowComponent = (props) => (
  <div>{props.data}</div>
);

const MyComp = with('Hello')(LowComponent)
```

生命周期
---

Hooks
---


另见
----

- [反应生命周期方法图](https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/)