1. context
- 创建一个Context对象
const MyContext = React.createContext(defaultValue);
注意 : 将 undefined 传递给 Provider 时,消费组件的 defaultValue 不会生效。
- context.Provider
- 当 Provider 的 value 值发生变化时,它内部的所有消费组件都会重新渲染。Provider 及其内部 consumer 组件都不受制于 shouldComponentUpdate 函数,因此当 consumer 组件在其祖先组件退出更新的情况下也能更新。
3.contextType
class MyClass extends React.Component {
static contextType = MyContext;
render() {
let value = this.context;
/* 基于这个值进行渲染工作 */
}}
//也可以在类的外部写成如下: Mycontext是在2中定义的
My.contextType = Mycontext
- Context.Consumer
{ value => /* 基于 context 值进行渲染*/ }
这里,React 组件也可以订阅到 context 变更。这能让你在函数式组件中完成订阅 context。
这需要函数作为子元素(function as a child)这种做法。这个函数接收当前的 context 值,返回一个 React 节点。传递给函数的 value 值等同于往上组件树离这个 context 最近的 Provider 提供的 value 值。如果没有对应的 Provider,value 参数等同于传递给 createContext() 的 defaultValue。
- 动态Context
import React from 'react';
const themes = {
light: {
color: 'blue',
background: 'red',
},
dark: {
color: '#ffffff',
background: '#000000',
},
};
const ThemeContext = React.createContext(
themes.dark // 默认值
);
class ThemedButton extends React.Component {
static contextType = ThemeContext;
render() {
let props = this.props;
let theme = this.context;
console.log(props,theme)
return (
);
}
}
function Toolbar(props) {
return (
{props.changeTheme?'我是用的上级传下来的属性':'我是默认值'}
);
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
theme: themes.light,
};
this.toggleTheme = () => {
this.setState(state => ({
theme:
state.theme === themes.dark ? themes.light : themes.dark,
}));
};
}
render() {
// 在 ThemeProvider 内部的 ThemedButton 按钮组件使用 state 中的 theme 值,
// 而外部的组件使用默认的 theme 值
return (
<>
>
);
}
}
export default App;
2.错误边界
1.注意错误边界无法捕获以下场景中产生的错误:
事件处理(了解更多)
异步代码(例如 setTimeout 或 requestAnimationFrame 回调函数)
服务端渲染
它自身抛出来的错误(并非它的子组件)
- 如果一个 class 组件中定义了 static getDerivedStateFromError() 或 componentDidCatch() 这两个生命周期方法中的任意一个(或两个)时,那么它就变成一个错误边界。当抛出错误后,请使用 static getDerivedStateFromError() 渲染备用 UI ,使用 componentDidCatch() 打印错误信息。
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// 更新 state 使下一次渲染能够显示降级后的 UI
return { hasError: true };
}
componentDidCatch(error, info) {
// 你同样可以将错误日志上报给服务器
logErrorToMyService(error, info);
}
render() {
if (this.state.hasError) {
// 你可以自定义降级后的 UI 并渲染
return Something went wrong.
;
}
return this.props.children;
}}
Refs转发
定义 :Ref 转发是一项将 ref 自动地通过组件传递到其一子组件的技巧。对于大多数应用中的组件来说,这通常不是必需的。但其对某些组件,尤其是可重用的组件库是很有用的。最常见的案例如下所述。
- 何时使用Refs
管理焦点,文本选择或媒体播放。
触发强制动画。
集成第三方 DOM 库
- 创建Refs:Refs 是使用 React.createRef() 创建的,并通过 ref 属性附加到 React 元素。在构造组件时,通常将 Refs 分配给实例属性,以便可以在整个组件中引用它们。
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
render() {
return ;
}
}
- 访问Refs:当 ref 被传递给 render 中的元素时,对该节点的引用可以在 ref 的 current 属性中被访问。
const node = this.myRef.current;
- ref 的值根据节点的类型而有所不同:
当 ref 属性用于 HTML 元素时,构造函数中使用 React.createRef() 创建的 ref 接收底层 DOM 元素作为其 current 属性。
当 ref 属性用于自定义 class 组件时,ref 对象接收组件的挂载实例作为其 current 属性。
你不能在函数组件上使用 ref 属性,因为他们没有实例。
Fragments
- 定义:Fragments 允许你将子列表分组,而无需向 DOM 添加额外节点。
< Fragments > < /Fragments > 或者<>>
高阶组件
- 定义:高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。
- 高阶组件是参数为组件,返回值为新组件的函数。
- 注意:HOC 不会修改传入的组件,也不会使用继承来复制其行为。相反,HOC 通过将组件包装在容器组件中来组成新组件。HOC 是纯函数,没有副作用。
- 虽然高阶组件的约定是将所有 props 传递给被包装组件,但这对于 refs 并不适用。那是因为 ref 实际上并不是一个 prop - 就像 key 一样,它是由 React 专门处理的。如果将 ref 添加到 HOC 的返回组件中,则 ref 引用指向容器组件,而不是被包装组件。
深入JSX
- 实际上,JSX 是 React.createElement(component, props, ...children) 函数的语法糖。
- 大写字母开头的 JSX 标签意味着它们是 React 组件。这些标签会被编译为对命名变量的直接引用,所以,当你使用 JSX
表达式时,Foo 必须包含在作用域内。
- 如果你没给 prop 赋值,它的默认值是 true
//这俩表达式完全等价
- 如果你已经有了一个 props 对象,你可以使用展开运算符... 来在 JSX 中传递整个 props 对象
function App1() {
return ;}
function App2() {
const props = {firstName: 'Ben', lastName: 'Hector'};
return ;
}
- false, null, undefined, and true 是合法的子元素。但它们并不会被渲染。以下的 JSX 表达式渲染结果相同;
- 值得注意的是有一些 “falsy” 值,如数字 0,仍然会被 React 渲染。例如,以下代码并不会像你预期那样工作,因为当 props.messages 是空数组时,0 仍然会被渲染:
{props.messages.length &&
}
要解决这个问题,确保 && 之前的表达式总是布尔值:
{props.messages.length > 0 &&
}
反之,如果你想渲染 false、true、null、undefined 等值,你需要先将它们转换为字符串:
My JavaScript variable is {String(myVariable)}
.
性能优化
确保你正在使用压缩后的生产版本。
Immutable.js
更多请自行百度
Portals
定义:Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案。
- 第一个参数(child)是任何可渲染的 React 子元素,例如一个元素,字符串或 fragment。第二个参数(container)是一个 DOM 元素。
ReactDOM.createPortal(child, container)
- 通常来讲,当你从组件的 render 方法返回一个元素时,该元素将被挂载到 DOM 节点中离其最近的父节点:
render() {
// React 挂载了一个新的 div,并且把子元素渲染其中
return (
{this.props.children}
);
}
然而,有时候将子元素插入到 DOM 节点中的不同位置也是有好处的:
render() {
// React 并*没有*创建一个新的 div。它只是把子元素渲染到 `domNode` 中。
// `domNode` 是一个可以在任何位置的有效 DOM 节点。
return ReactDOM.createPortal(
this.props.children, domNode
);
}
一个 portal 的典型用例是当父组件有 overflow: hidden 或 z-index 样式时,但你需要子组件能够在视觉上“跳出”其容器。例如,对话框、悬浮卡以及提示框:
使用 PropTypes 进行类型检查
注意 : 自 React v15.5 起,React.PropTypes 已移入另一个包中。请使用 prop-types 库 代替。
使用方法
import PropTypes from 'prop-types';
class Greeting extends React.Component {
render() {
return (
Hello, {this.props.name}
);
}
}
Greeting.propTypes = {
name: PropTypes.string
};
import PropTypes from 'prop-types';
MyComponent.propTypes = {
// 你可以将属性声明为 JS 原生类型,默认情况下
// 这些属性都是可选的。
optionalArray : PropTypes.array,
optionalBool : PropTypes.bool,
optionalFunc : PropTypes.func,
optionalNumber : PropTypes.number,
optionalObject : PropTypes.object,
optionalString : PropTypes.string,
optionalSymbol : PropTypes.symbol,
// 任何可被渲染的元素(包括数字、字符串、元素或数组)
// (或 Fragment) 也包含这些类型。
optionalNode : PropTypes.node,
// 一个 React 元素。
optionalElement : PropTypes.element,
// 一个 React 元素类型(即,MyComponent)。
optionalElementType : PropTypes.elementType,
// 你也可以声明 prop 为类的实例,这里使用
// JS 的 instanceof 操作符。
optionalMessage : PropTypes.instanceOf(Message),
// 你可以让你的 prop 只能是特定的值,指定它为
// 枚举类型。
optionalEnum : PropTypes.oneOf(['News', 'Photos']),
// 一个对象可以是几种类型中的任意一个类型
optionalUnion : PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(Message)
]),
// 可以指定一个数组由某一类型的元素组成
optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
// 可以指定一个对象由某一类型的值组成
optionalObjectOf: PropTypes.objectOf(PropTypes.number),
// 可以指定一个对象由特定的类型值组成
optionalObjectWithShape: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
}),
// An object with warnings on extra properties
optionalObjectWithStrictShape: PropTypes.exact({
name: PropTypes.string,
quantity: PropTypes.number
}),
// 你可以在任何 PropTypes 属性后面加上 `isRequired` ,确保
// 这个 prop 没有被提供时,会打印警告信息。
requiredFunc: PropTypes.func.isRequired,
// 任意类型的数据
requiredAny: PropTypes.any.isRequired,
// 你可以指定一个自定义验证器。它在验证失败时应返回一个 Error 对象。
// 请不要使用 `console.warn` 或抛出异常,因为这在 `onOfType` 中不会起作用。
customProp: function(props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error(
'Invalid prop `' + propName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
},
// 你也可以提供一个自定义的 `arrayOf` 或 `objectOf` 验证器。
// 它应该在验证失败时返回一个 Error 对象。
// 验证器将验证数组或对象中的每个值。验证器的前两个参数
// 第一个是数组或对象本身
// 第二个是他们当前的键。
customArrayProp: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {
if (!/matchme/.test(propValue[key])) {
return new Error(
'Invalid prop `' + propFullName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
})};
React.Component
render() 方法是 class 组件中唯一必须实现的方法。
constructor()
如果不初始化 state 或不进行方法绑定,则不需要为 React 组件实现构造函数。
- 通常,在 React 中,构造函数仅用于以下两种情况:
通过给 this.state 赋值对象来初始化内部 state。
为事件处理函数绑定实例
- 在 constructor() 函数中不要调用 setState() 方法。如果你的组件需要使用内部 state,请直接在构造函数中为 this.state 赋值初始 state
constructor(props) {
super(props);
// 不要在这里调用 this.setState()
this.state = { counter: 0 };
this.handleClick = this.handleClick.bind(this);
}
- 避免将 props 的值复制给 state!这是一个常见的错误:
componentDidMount()钩子
- 调用时机以及主要作用
componentDidMount() 会在组件挂载后(插入 DOM 树中)立即调用。
依赖于 DOM 节点的初始化应该放在这里。如需通过网络请求获取数据,此处是实例化请求的好地方。
componentDidUpdate(prevProps, prevState, snapshot)
componentDidUpdate() 会在更新后会被立即调用。首次渲染不会执行此方法。
你也可以在 componentDidUpdate() 中直接调用 setState(),但请注意它必须被包裹在一个条件语件里,否则会导致死循环。
注意 : 如果 shouldComponentUpdate() 返回值为 false,则不会调用 componentDidUpdate()。
componentWillUnmount()
componentWillUnmount() 会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等。
componentWillUnmount() 中不应调用 setState(),因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它。
shouldComponentUpdate(nextProps, nextState) 不常用
此方法仅作为性能优化的方式而存在。不要企图依靠此方法来“阻止”渲染,因为这可能会产生 bug。你应该考虑使用内置的 PureComponent 组件,而不是手动编写
首次渲染或使用 forceUpdate() 时不会调用该方法。
返回值默认为true , 若为false则不渲染该组件,但子组件的state变化依旧会进行渲染子组件
static getDerivedStateFromProps(props, state)
调用时机 : 会在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新 state(相当于merge),如果返回 null则不更新任何内容。
getSnapshotBeforeUpdate(prevProps, prevState)
- 调用时机 : getSnapshotBeforeUpdate() 在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期的任何返回值将作为参数传递给 componentDidUpdate()。
static getDerivedStateFromError(error)
此生命周期会在后代组件抛出错误后被调用。 它将抛出的错误作为参数,并返回一个值以更新 state
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// 更新 state 使下一次渲染可以显降级 UI
return { hasError: true };
}
render() {
if (this.state.hasError) {
// 你可以渲染任何自定义的降级 UI
return Something went wrong.
;
}
return this.props.children;
}}
componentDidCatch(error, info)
此生命周期在后代组件抛出错误后被调用。 它接收两个参数:
error —— 抛出的错误
info —— 带有 componentStack key 的对象,其中包含有关组件引发错误的栈信息。
setState()
这个是异步的 , 如果想再一次回调中执行多次setState(),请使用回调函数的方式或者componentDidUpdate
除非 shouldComponentUpdate() 返回 false,否则 setState() 将始终执行重新渲染操作。
函数式setState
this.setState((state, props) => {
return { counter: state.counter + props.step };
}
);
- 直接赋值式
this.setState({quantity: 2})
forceUpdate(callback)
默认情况下,当组件的 state 或 props 发生变化时,组件将重新渲染。如果 render() 方法依赖于其他数据,则可以调用 forceUpdate() 强制让组件重新渲染。
调用 forceUpdate() 将致使组件调用 render() 方法,此操作会跳过该组件的 shouldComponentUpdate()。但其子组件会触发正常的生命周期方法,包括 shouldComponentUpdate() 方法。如果标记发生变化,React 仍将只更新 DOM。
defaultProps
defaultProps 可以为 Class 组件添加默认 props。这一般用于 props 未赋值,但又不能为 null 的情况。例如:
class CustomButton extends React.Component {
// ...
}
CustomButton.defaultProps = {
color: 'blue'
};
如果未提供 props.color,则默认设置为 'blue'
render() {
return ;
// props.color 将设置为 'blue'
}
如果 props.color 被设置为 null,则它将保持为 null
render() {
return ;
// props.color 将保持是 null
}
ReactDOM
如果你使用一个