# 无障碍
其实是通过标准 html 技术实现的。
# 代码分割
- 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>
);
}
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"));
2
3
4
5
6
7
8
# Context
- 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} />;
}
}
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 更好的解决方案;
- 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
指定 React 元素类型 React 必须在作用域内 在 JSX 类型中使用点语法 用户定义的组件必须以大写字母开头 在运行时选择类型
JSX 中的 Props
字符串字面量 Props 默认值为 “True” 属性展开JSX 中的子元素 字符串字面量 JSX 子元素 JavaScript 表达式作为子元素 函数作为子元素 布尔类型、Null 以及 Undefined 将会忽略
# 性能优化
- 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>
);
}
}
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
- React.PureComponent,使用 React.PureComponent 来代替手写 shouldComponentUpdate
# Portals
Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案。
ReactDOM.createPortal(child, container)
第一个参数(child)是任何可渲染的 React 子元素,例如一个元素,字符串或 fragment。第二个参数(container)是一个 DOM 元素。
# Profiler
Profiler API测量渲染一个 React 应用多久渲染一次以及渲染一次的“代价”。 它的目的是识别出应用中渲染较慢的部分
# 不使用 ES6
为了保险起见,以下三种做法都是可以的:
- 在 constructor 中绑定方法。
constructor(props) {
super(props);
this.state = {message: 'Hello!'};
// 这一行很重要!
this.handleClick = this.handleClick.bind(this);
}
2
3
4
5
6
使用箭头函数,比如:
onClick={(e) => this.handleClick(e)}。继续使用 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>;
},
});
2
3
4
5
6
7
8
9
10
11
12
13
- 目前还处于试验性阶段的语法
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>;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 不使用 JSX
React 并不强制要求使用 JSX。当你不想在构建环境中配置有关 JSX 编译时,不在 React 中使用 JSX 会更加方便。
# 协调
- 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 Props 与 React.PureComponent一起使用时要小心
如果你在 render 方法里创建函数,那么使用 render prop 会抵消使用 React.PureComponent 带来的优势。因为浅比较 props 的时候总会得到 false,并且在这种情况下每一个 render 对于 render prop 将会生成一个新的值。
# 静态类型检查
- Flow
- 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,
};
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