# 无障碍

其实是通过标准 html 技术实现的。

# 代码分割

  1. React.lazy ----能够让你想渲染常规组件一样处理动态引入

WARNING

React.lazy 和 Suspense 技术还不支持服务端渲染。如果想要在使用服务端渲染的应用中使用,推荐 Loadable Components 这个库

(1) React.lazy 接受一个函数,这个函数需要动态调用 import()。它必须返回一个 Promise,该 Promise 需要 resolve 一个 defalut export 的 React 组件。

eg:const OtherComponent = React.lazy(() => import('./OtherComponent'));

(2) 在 Suspense 组件中渲染 lazy 组件,如此使得我们可以使用在等待加载 lazy 组件时做优雅降级(如 loading 指示器等)。fallback 属性接受任何在组件加载过程中你想展示的 React 元素。可以将 Suspense组件置于懒加载组件之上的任何位置,可以用一个 Suspense 组件包裹多个懒加载组件。

import React, { Suspense } from "react";

const OtherComponent = React.lazy(() => import("./OtherComponent"));
const AnotherComponent = React.lazy(() => import("./AnotherComponent"));

function MyComponent() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <section>
          <OtherComponent />
          <AnotherComponent />
        </section>
      </Suspense>
    </div>
  );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

(3) React.lazy 目前只支持默认导出(default exports)。如果你想被引入的模块使用命名导出(named exports),你可以创建一个中间模块,来重新导出为默认模块。这能保证 tree shaking 不会出错,并且不必引入不需要的组件。

// ManyComponents.js
export const MyComponent = /* ... */;
export const MyUnusedComponent = /* ... */;
// MyComponent.js
export { MyComponent as default } from "./ManyComponents.js";
// MyApp.js
import React, { lazy } from 'react';
const MyComponent = lazy(() => import("./MyComponent.js"));
1
2
3
4
5
6
7
8

# Context

  1. Context----上下文提供了一个无需为每层组件手动添加道具,就能在组件树间进行数据传递的方法;不通过 props,在组件树之间共享全局数据。设计目的是为了共享那些对于一个组件树而言是“全局”的数据,例如当前认证的用户、主题或首选语言
// Context 可以让我们无须明确地传遍每一个组件,就能将值深入传递进组件树。
// 为当前的 theme 创建一个 context(“light”为默认值)。
const ThemeContext = React.createContext("light");
class App extends React.Component {
  render() {
    // 使用一个 Provider 来将当前的 theme 传递给以下的组件树。
    // 无论多深,任何组件都能读取这个值。
    // 在这个例子中,我们将 “dark” 作为当前的值传递下去。
    return (
      <ThemeContext.Provider value="dark">
        <Toolbar />
      </ThemeContext.Provider>
    );
  }
}

// 中间的组件再也不必指明往下传递 theme 了。
function Toolbar() {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

class ThemedButton extends React.Component {
  // 指定 contextType 读取当前的 theme context。
  // React 会往上找到最近的 theme Provider,然后使用它的值。
  // 在这个例子中,当前的 theme 值为 “dark”。
  static contextType = ThemeContext;
  render() {
    return <Button theme={this.context} />;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

使用 Context 之前到考虑:Context 主要应用场景在于很多不同层级的组件需要访问同样的一些数据。请谨慎使用,因为会使得组件的复用性变差;

如果你只是想避免层层传递一些属性,组件组合有时候是一个比 context 更好的解决方案;

  1. API

① React.createContext

② Context.Provider

③ Class.contextType

④Context.Consumer

⑤Context.displayName

# 错误边界

错误边界是一种 React 组件,这种组件可以捕获并打印发生在其子组件树任何位置的 JavaScript 错误,并且会渲染出备用 UI,

而不是渲染那些崩溃了的子组件。错误边界在渲染期间、生命周期方法和整个组件树的构造函数中捕获错误;

注意:错误边界无法捕获一下场景中产生的错误:事件处理;异步代码(例如:setTimeout 或 requestAnimationFrame 回调函数);服务端渲染;它自身抛出来的错误(并非他的子组件)

# Refs 转发

ref 转发是一项将 ref 自动地通过组件传递到其一子组件的技巧。Ref 转发不仅限于 DOM 组件,你也可以转发 refs 到 class 组件实例中。

# Fragments

React 中一个常见模式是一个组件返回多个元素。Fragments 允许你将子列表分组,而无需向 DOM 添加额外节点;

# 高阶组件

高阶组件(HOC)是 React 中用于重用组件逻辑的高级技术。HOC 本身不是 React API 一部分。它们是 React 组成性质的一种模式。

高阶组件是一个获取组件并返回新组建的函数;

const EnhanceComponent = higherOrderComponent(WrapperComponent);

组件将 props 转换为 UI,而高阶组件将组件转换为另一个组件;

# 深入 JSX

  1. 指定 React 元素类型 React 必须在作用域内 在 JSX 类型中使用点语法 用户定义的组件必须以大写字母开头 在运行时选择类型

  2. JSX 中的 Props
    字符串字面量 Props 默认值为 “True” 属性展开

  3. JSX 中的子元素 字符串字面量 JSX 子元素 JavaScript 表达式作为子元素 函数作为子元素 布尔类型、Null 以及 Undefined 将会忽略

# 性能优化

  1. shouldComponentUpdate ,如果你的组件只有当 props.color 或者 state.count 的值改变才需要更新时,你可以使用 shouldComponentUpdate 来进行检查:
class CounterButton extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 1 };
  }

  shouldComponentUpdate(nextProps, nextState) {
    if (this.props.color !== nextProps.color) {
      return true;
    }
    if (this.state.count !== nextState.count) {
      return true;
    }
    return false;
  }

  render() {
    return (
      <button
        color={this.props.color}
        onClick={() => this.setState((state) => ({ count: state.count + 1 }))}
      >
        Count: {this.state.count}
      </button>
    );
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  1. React.PureComponent,使用 React.PureComponent 来代替手写 shouldComponentUpdate

# Portals

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

ReactDOM.createPortal(child, container)

第一个参数(child)是任何可渲染的 React 子元素,例如一个元素,字符串或 fragment。第二个参数(container)是一个 DOM 元素。

# Profiler

Profiler API测量渲染一个 React 应用多久渲染一次以及渲染一次的“代价”。 它的目的是识别出应用中渲染较慢的部分

# 不使用 ES6

为了保险起见,以下三种做法都是可以的:

  1. 在 constructor 中绑定方法。
  constructor(props) {
    super(props);
    this.state = {message: 'Hello!'};
    // 这一行很重要!
    this.handleClick = this.handleClick.bind(this);
  }
1
2
3
4
5
6
  1. 使用箭头函数,比如:onClick={(e) => this.handleClick(e)}。

  2. 继续使用 createReactClass。

var SayHello = createReactClass({
  getInitialState: function() {
    return { message: "Hello!" };
  },

  handleClick: function() {
    alert(this.state.message);
  },

  render: function() {
    return <button onClick={this.handleClick}>Say hello</button>;
  },
});
1
2
3
4
5
6
7
8
9
10
11
12
13
  1. 目前还处于试验性阶段的语法
class SayHello extends React.Component {
  constructor(props) {
    super(props);
    this.state = { message: "Hello!" };
  }
  // 警告:这种语法还处于试验性阶段!
  // 在这里使用箭头函数就可以把方法绑定给实例:
  handleClick = () => {
    alert(this.state.message);
  };

  render() {
    return <button onClick={this.handleClick}>Say hello</button>;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 不使用 JSX

React 并不强制要求使用 JSX。当你不想在构建环境中配置有关 JSX 编译时,不在 React 中使用 JSX 会更加方便。

# 协调

  1. Diffing 算法

(1)比对不同类型的元素 当根节点为不同类型的元素时,React 会拆卸原有的树并且建立起新的树。举个例子,当一个元素从<a> 变成 <img>,从 <Article> 变成 <Comment>,或从 <Button> 变成 <div> 都会触发一个完整的重建流程。

(2)比对同一类型的元素 当比对两个相同类型的 React 元素时,React 会保留 DOM 节点,仅比对及更新有改变的属性。比如:

(3)比对同类型的组件元素 当一个组件更新时,组件实例保持不变,这样 state 在跨越不同的渲染时保持一致。React 将更新该组件实例的 props 以跟最新的元素保持一致,并且调用该实例的 componentWillReceiveProps() 和 componentWillUpdate() 方法。

下一步,调用 render() 方法,diff 算法将在之前的结果以及新的结果中进行递归。

(4)对子节点进行递归 在默认条件下,当递归 DOM 节点的子元素时,React 会同时遍历两个子元素的列表;当产生差异时,生成一个 mutation。

在子元素列表末尾新增元素时,更变开销比较小

# Refs & DOM

Refs 提供了一种方式,允许我们访问 DOM 节点或在 render 方法中创建的 React 元素。

# Render Props

术语 render prop 是指一种在 React 组件之间使用一个值为函数的 prop 共享代码的简单技术。

Render PropsReact.PureComponent一起使用时要小心 如果你在 render 方法里创建函数,那么使用 render prop 会抵消使用 React.PureComponent 带来的优势。因为浅比较 props 的时候总会得到 false,并且在这种情况下每一个 render 对于 render prop 将会生成一个新的值。

# 静态类型检查

  1. Flow
  2. TypeScript

# 严格模式

StrictMode是一个用来突出显示应用程序中潜在问题的工具。与 Fragment 一样,StrictMode 不会渲染任何可见的 UI。它为其后代元素触发额外的检查和警告。

# 使用 PropTypes 类型检查

React 也内置了一些类型检查的功能,要在组件的 props 上进行类型检查,你只需配置特定的 propTypes 属性:

import PropTypes from "prop-types";

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

Greeting.propTypes = {
  name: PropTypes.string,
};
1
2
3
4
5
6
7
8
9
10
11

# 非受控组件

在大多数情况下,我们推荐使用 受控组件 来处理表单数据。在一个受控组件中,表单数据是由 React 组件来管理的。另一种替代方案是使用非受控组件,这时表单数据将交由 DOM 节点来处理。

要编写一个非受控组件,而不是为每个状态更新都编写数据处理函数,你可以 使用 ref 来从 DOM 节点中获取表单数据。

# Web Components

Web Components 为可复用组件提供了强大的封装,而 React 则提供了声明式的解决方案,使 DOM 与数据保持同步。两者旨在互补。作为开发人员,可以自由选择在 Web Components 中使用 React,或者在 React 中使用 Web Components,或者两者共存。

# 参考

https://react.docschina.org/docs/accessibility.html