一、React 顶层 API
顶层API就是顶层的react,
import React from 'react'
这种
react中的函数组件性能优化只有两个方向(除key之外):第一个为减少重新 render 的次数,因为父组件重新渲染的时候经常会让子组件也重新渲染。第二个为减少重复计算,因为函数组件每次渲染,就会重新开始创建组件里面的所有值,也就会再一次的进行所有的计算。
- (1)isValidElement():验证对象是否为 React 元素,返回值为 true 或 false。
React.isValidElement(object)
- (2)React.Children: React.Children 提供了用于处理 this.props.children 不透明数据结构的实用方法。如:
React.Children.map(children, function[(thisArg)])
1、React.Component
React.Component 是使用 ES6 classes 方式定义 React 组件的基类,如果使用类组件,那么自己写的组件就需要集成这个React.Component
class Greeting extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
2、React.PureComponent
React.PureComponent 与 React.Component 很相似。两者的区别在于 React.Component自带了 shouldComponentUpdate(),即在传入当前组件的prevProps和 nextProps是相同的情况下,react不会重新渲染当前组件。简单说在父组件重新渲染的时候,如果传入子组件的props是相同的,那么子组件不会重新渲染。就是减少子组件的render次数。具体操作和下面的React.memo差不多的,都是浅比较,不过这个是用于类组件
这里还有一个需要注意的点,就是使用这个的时候,如果给子组件传的是一个箭头函数(匿名函数每次都会产生新地址),则会使PureComponent的优化失效。解决办法是给子组件传的函数,在定义的时候就用箭头函数
class Greeting extends React.PureComponent {
demo2Func = ()=>{} // 在定义函数的时候弄成一个箭头函数,就可以解决this的问题了,也可也解决优化的问题
render() {
return <h1>Hello, {this.props.name}
<Child1 demo1={()=>{count}} /> // 这样传函数,会让PureComponent的优化失效
<Child2 demo2={this.demo2Func} /> // 这样传就没问题了
</h1>;
}
}
3、React.memo()函数
React.memo()函数是用来进行性能优化的。被React.memo包裹的函数组件,如果传入的两个props在浅比较的情况下相同,那么React 将跳过此次渲染并直接复用最近一次渲染的结果(渲染指的是render而不是componentDidMount钩子)。就是减少子组件的render次数。但是如果用了useContext,当 context 发生变化时,它仍会重新渲染。这东西是PureComponent的在函数组件中的使用,因为PureComponent只能在class组件中使用
- 使用:
React.memo(component, compareFunc)
,接收两个参数,如下
- component: 即一个需要使用memo的函数组件
- compareFunc: 这个是一个比较函数,用来控制是否重新渲染组件,返回true则复用渲染,false则重新渲染。接收参数为之前的props和现在传入的props,如
compareFunc(prevProps, nextProps)
。可以不传这个参数
- 使用实例:如下,现在有一个显示时间的组件,每一秒都会重新渲染一次,他有一个子组件Child,但是对于这个子组件我们肯定不希望也跟着渲染,所以这里就可以用react.memo来包裹子组件
- 使用前提,只要父组件进行重新渲染,即使子组件的props或state没有做出任何改变,也会同样进行重新渲染
有一个问题是,如果给子组件传一个函数,则会让memo的优化失效。解决办法为用useCallBack()包括需要传的函数
// 父组件parent
function parent(props) {
const [count, setCount] = useState(0);
useEffct(()=>{
setInterval(()=>{setCount(new Date())},1000); // 这里1s执行一次,然后重新渲染count,导致整个组件重新渲染
},[]);
return (
<div>
<Child seconds={1}/> // 这里是一个子组件,由于值没有更新,我们肯定是不希望父组件一直刷新的时候,自己也刷新的
<div>{count.toString()}</div>
</div>
);
}
// 子组件Child
function Child(props){}
export default connect(() => {
return {};
})(Form.create()(React.memo(Test))); // 这里直接包裹组件
// export default React.memo(Child,(prevProps, nextProps) =>{return prevProps === nextProps;});
4、React.lazy()函数
React 16.6就支持了
- React.lazy() 允许你定义一个懒加载的组件。这有助于缩减 bundle 的体积,并延迟加载在初次渲染时未用到的组件。还是很好用的. 被React.lazy包裹的组件,在没有被使用的时候就不会被打包进bundle,只有在使用的时候才打包。如果是普通的import方式引入的,则没有被使用也会被打包进bundle,所以就会导致bundle很大,首次加载很慢
- 接收的参数为一个函数,这个函数返回一个代表react组件的promise
- 返回值:返回值,应该就是对应的promise组件了
- React.lazy()现在只支持默认导出
5、React.Suspense组件
React 16.6就支持了
<React.Suspense>
这个组件是配合上面的React.lazy()函数一起来使用的,用来包裹对应的react.lazy组件。一个suspense可以包裹多个懒加载组件
- fallback属性: 这个React.Suspense组件的属性,值为一个字符串或者reactElement。这个属性表示React.Suspense组件里面包裹的React.lazy组件正在被加载的时候(即promise的状态为pending的时候),显示在页面上面的占位符。当promise的状态为resolve,这个占位符就消失了
// 普通情况,OtherComponent组件 是不会被请求直到MyComponent开始渲染。但是,因为我们静态导入了 OtherComponent,它会和 MyComponent 一起打包
import OtherComponent from './OtherComponent';
const MyComponent = () => {
<div>
<OtherComponent />
</div>
};
// 这个组件是懒加载的。这里OtherComponent就不会被直接被打包了
import React, { Suspense } from 'react';
const LazyComponent = React.lazy(() => import('./OtherComponent'));
const MyComponent = () => {
<div>
<Suspense fallback={<div>Loading...</div>}> // LazyComponent组件正在被加载的时候,显示在页面的为<div>Loading...</div>
<LazyComponent />
</Suspense>
</div>
}
6、React.createContext()函数
- React.createContext() 函数创建一个Context 对象,这个对象是用来在父组件中存数据,然后可以不用props传值,就可以直接在孙子组件中使用的
- 返回值,返回值为一个context对象,这个对象包含两个组件Provider和Consumer。
- Provider组件用在父组件中,用来包装子组件。有一个value属性,就是子组件中获取到的值
- Consumer组件用在子组件中,里面的值为一个函数,函数的参数就是provider里面的value。但是,这个Consumer组件不是很好用,一般不用。
- contextType属性: 这个是在子组件中使用,用来替代Consumer组件,即可以不用Consumer组件来获取provider的value值。
- 这个属性只能在class组件中使用,并且即使这个子组件有多个consumer ,contextType 也只能有一个。
- 具体使用方法就是,在class组件中,
static contextType = ThemeContext
,后面的ThemeContext为一个context对象。之后,在组件里面,就可以直接用this.context,来获取到provider里面的value值了。- 当然如果想在函数组件中使用,就需要用到hook了
// test.js
import React, {PureComponent,createContext } from 'react';import { Button } from 'antd';import Test1 from './test1';
export const MyContext = createContext(null); // 把context导出,因为后续是需要到另外的文件里面使用的
export const MyContext2 = createContext(null);
class Test extends PureComponent {
state = {count: 1,go: 3333,};
render () {return (<div>
<Button onClick={()=>{this.setState({count: count + 1});}}>click me?????</Button>
<MyContext.Provider value={this.state.count}> // 使用provider
<MyContext2.Provider value={this.state.go}>
<Test1 />
</MyContext2.Provider>
</MyContext.Provider>
</div>);}
}
// test1.js
import React, {PureComponent,} from 'react';import Test2 from './test2';
class Test1 extends PureComponent {
render () {return (<div><Test2></Test2></div>);}
}
// test2.js
import React, {PureComponent, useState, useEffect, useRef } from 'react';
import {MyContext, MyContext2} from './test'; // 导入两个context,使用的是命名空间导入
class Test2 extends PureComponent {
static contextType = MyContext; // 使用contextType
render () {
console.log(this.context); // 这里就可以从this上面读取到对应的context了。 默认是1
return (<div>
<MyContext.Consumer> // 这里是在用consumer组件,不过一般是不用这个的
{(value) =>(<div>res: {value}</div>)}
</MyContext.Consumer>
</div>);
}
}
二、React.Component
React 的组件可以定义为 class 或函数的形式。class 组件目前提供了更多的功能,这些功能将在此章节中详细介绍。如需定义 class 组件,需要继承 React.Component
在 React.Component 的子类中有个必须定义的 render() 函数
1、组件的生命周期函数
这个生命周期函数,依然是只有class组件才有
和vue一样,react也有一个生命周期。生命周期分为三个阶段,分别是挂载阶段、更新阶段、卸载阶段
(1)挂载阶段
这阶段为,当组件实例被创建并插入 DOM 中时;下述顺序为,其生命周期调用顺序
- <1>constructor(props): 是最先被执行的,我们通常在构造函数里初始化state对象或者给自定义事件绑定this(这个绑定this是没有必要的,用箭头函数就可以避免这个this不可用问题)。
- 如果不初始化 state 或不进行方法绑定,则不需要为 React 组件实现构造函数
- 在构造函数中,应在其他语句之前前调用 super(props)。否则,this.props 在构造函数中可能会出现未定义的 bug
- 只能在构造函数中直接为 this.state赋值,在构造函数中一般不用setState()
- 避免将 props 的值直接赋值给 state。因为这样的话,更新props中的属性,并不会使state更新(原理和vue类似)
constructor(props) {
super(props);
// 不要这样做
this.state = { color: props.color };
this.handleClick = this.handleClick.bind(this); // handleClick为自定义事件
}
- <2>static getDerivedStateFromProps(nextProps, prevState): 在初始挂载及后续组件更新时都会被调用,返回一个对象来更新 state,如果返回 null 则不更新任何内容。不过这个用的很少。Derived(派生的)
- 当我们接收到新的属性想去修改我们state的时候使用
- 此方法无权访问组件实例
- <3>render(): 是class 组件中唯一必须实现的方法;用来渲染dom。如果render返回的为一个组件,那么这个组件相关的配置信息,也写在render函数里面,不过是写在return的上面。比如,要写要给table组件,table组件里面的分页配置这些,也写在render里面
- 当 render 被调用时,它会检查 this.props 和 this.state 的变化并返回以下类型之一
- React 元素: 通常通过 JSX 创建
- 数组或 fragments: 使得 render 方法可以返回多个元素
- Portals: 可以渲染子节点到不同的 DOM 子树中
- 字符串或数值类型: 它们在 DOM 中会被渲染为文本节点
- 布尔类型或 null: 什么都不渲染
- 如果 shouldComponentUpdate() 返回 false,则不会调用 render()
- render() 函数应该为纯函数,只返回需要渲染的东西,不应该包含其它的业务逻辑
- <4>componentDidMount(): 是在组件挂载后(插入 DOM 树中)调用,此时我们可以获取到DOM节点并操作。这个钩子只在页面刷新(即,组件初始化)的时候调用。
- 依赖于 DOM 节点的初始化应该放在这里。比如通过网络请求获取数据,就在这里写
- 可以在 componentDidMount() 里直接调用 setState()。它将触发额外渲染,但此渲染会发生在浏览器更新屏幕之前。如此保证了即使在 render() 两次调用的情况下,用户也不会看到中间状态
(2)更新阶段
这阶段为,当组件的 props 或 state或者context 发生变化时会触发更新。下述顺序为,其生命周期调用顺序
- <1>static getDerivedStateFromProps(nextProps, prevState): 这个就是上面的那个函数,在初始挂载和组件更新的时候都会被调用
- <2>shouldComponentUpdate(nextProps, nextState): 在props 或 state 发生变化或父组件重新渲染时,shouldComponentUpdate() 会在渲染执行之前被调用;用来决定后续生命周期函数是否调用。这里有个问题就是,在没有用PureComponent和React.memo的情况下,只要父组件进行重新渲染,即使子组件的props或state没有做出任何改变,也会同样进行重新渲染
- 返回一个布尔值,true表示会触发重新渲染,false表示不会触发重新渲染。默认返回true,表示 state 每次发生变化组件都会重新渲染
- 首次渲染或使用 forceUpdate() 时不会调用该方法
- 返回 false 并不会阻止子组件在 state 更改时重新渲染
- <3>render(): 就是上面那个render。如果 shouldComponentUpdate() 返回 false,则不会调用 render()
- <4>getSnapshotBeforeUpdate(prevProps, prevState): 在最近一次渲染输出(提交到 DOM 节点)之前调用。Snapshot(快照)
- 有一个返回值snapshot,会作为第三个参数传给componentDidUpdate,如果你不想要返回值,可以返回null,此生命周期必须与componentDidUpdate搭配使用
- <5>componentDidUpdate(prevProps, prevState, snapshot): 会在在props或者state更新后会被立即调用,此时可以获取dom操作。prevProps为之前传入的属性,prevState为之前的state
- 如果仅仅是组件内部的state改变触发的更新,则,
prevProps === this.props// 为true
。如果是props改变触发的更新,则,prevState === this.state // 为true
- 当组件更新后,可以在此处对 DOM 进行操作
- 这里面直接调用 setState(),必须被包裹在一个条件语句里,否则会导致死循环。比如需要当props改变的时候修改state的话,条件语句就可以写
prevState == this.state
- 如果要在传入的props更新的时候触发一个函数,可以直接用
prevState === this.state && visible === true(如果是传入了visible参数,用来控制当前modal是否显示,显示的时候才触发更新)
,而不添加prevProps !== this.props
(3)卸载阶段
这阶段为,当组件从 DOM 中移除时会调用如下方法
componentWillUnmount()。组件卸载(销毁)即通过路由切换组件的时候,直接把原来的组件DOM移除。这里和useEffect hook是不同的,useEffect hook在组件销毁和、组件更新之前都会调用卸载函数
- <1>componentWillUnmount(): 会在组件==卸载(或者说组件销毁)==的时候直接调用。
- 在此方法中执行必要的清理操作,例如,清除定时器,取消网络请求或清除在 componentDidMount() 中创建的订阅,清理无效的DOM元素等垃圾清理工作
- componentWillUnmount() 中不应调用 setState(),因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它
(4)错误处理
当渲染过程,生命周期,或子组件的构造函数中抛出错误时,会调用如下方法:
- <1>static getDerivedStateFromError()
- <2>componentDidCatch(): 定义了这个声明周期函数,这个class组件就变成了一个错误边界。由于在react 16里面,ui的javascript崩溃的时候,整个应用程序都会崩溃,所以这个错误边界就是用来捕获这些错误,并且在页面渲染一些东西,让整个页面不崩溃。函数组件无法使用错误边界,所以还是不用这个算了。
2、其他 APIs
这部分主要是两个API,setState()和forceUpdate()
- <1>setState(updater[, callback]): 作用有两个第一个为,修改this.state的值,将组件对于state 的更改加入异步队列;第二个为触发dom更新,以改变dom上面的state。函数的返回值为undefined。接收两个参数,第一个参数为要和state合并的值,第二个参数为一个回调函数。
- (1)updater参数:这个参数可以是一个对象,也可以是一个函数
- 参数为对象:为对象的时候,会直接把这个对象与 state 进行浅合并
- 参数为函数:为函数的时候接收两个参数,
state, props
- state: 这个state为 当前最新的state,即为最近一次调用setState时候修改过的state,而不需要等异步更新。简单说就是在callback里面才访问的到的那个最新的state,具体说明见下面实例
- props: 也是最新的props
- 返回值:返回值需要为一个对象,然后依然是把这个对象和state进行浅合并
- (2)callback参数: 由于这个setState不是直接更新state,而是加入异步队列中;所以如果需要在修改完state之后直接读取state,则需要在这个回调函数中来操作,或者在
componentDidUpdate
生命周期函数中读取- 注:如果不用setState()这个函数来改变state,而直接给this.state赋值,那么又有下面这两种情况
- (1)直接给this.state赋值:这样赋值是无效的,赋值之后只有在当前函数中的this.state是刚赋的值;退出当前函数之后,this.state还是之前的值
- (2)直接给this.state上面的属性赋值:这样赋值是有效的,会让this.state的值进行修改,但是不能触发dom的更新
// 下面为使用this.setState函数来进行修改
state = {
count: 5555,
go: 44444
};
func = () => {
this.setState({count: 4});
this.state.count; // 5555。直接读取,是读取不到刚刚修改的值的。因为要经过异步,才可以同步到this上面
this.setState((state,props) => { // 4。这里用的函数的写法,读取到的是最新的值,不需要经过异步
return {count: 6}; // 返回的值,依然会和this.state进行浅合并
});
this.setState({count: 7}, ()=>{
this.state; // 7。这里回调里面也是获取的最新的值
});
}
// 下面为直接给this.state赋值。赋值无效
state = {count: 555}
func = () => {
console.log(this.state); // 退出函数再次进入之后,这个值依然是{count: 555}。所以下面的那句赋值是无效的
this.state = {count: 6};
console.log(this.state); // 赋值之后这里直接访问的话,出来的结果就是{count: 6}。但是退出函数就无效了
}
// 下面为直接给this.state上面的属性赋值。赋值有效,但是无法触发dom更新
state = {count: 555}
func = () => {
console.log(this.state); // 退出函数再次进入之后,这个值依然是{count: 6}。所以下面的那句赋值是有效的
this.state.count = 6;
console.log(this.state); // 赋值之后这里直接访问的话,出来的结果就是{count: 6}。
// this.setState({}); 如果加上这条语句,就可以把上面修改的state同步到dom更新里面了
}
render()=>{
return <div>{this.state.count}</div>; // 这里这个count值不会被改变,依然是555。所以直接改变this.state上面的属性值,不会触发dom的更新
}
- <2>component.forceUpdate(callback): 如果 render() 方法依赖于其他数据,则可以调用 forceUpdate() 强制让组件重新渲染。一般就不用这个了
3、Class 属性
这部分主要是两个Class的属性,defaultProps和displayName
- (1)defaultProps: 这个可以为 Class 组件添加默认 props。这一般用于 props 未赋值,但又不能为 null 的情况。只不过之前用,好像不行
class CustomButton extends React.Component {
// ...
}
CustomButton.defaultProps = { // 用了这个,CustomButton上面的props就有了一个color属性了
color: 'blue'
};
4、实例属性
这部分主要是两个实例属性,props和state
- (1)props:这个就相当于vue中的prop,一样的。定义在子组件标签上面的,就是props上面的数据。
- (2)state: 这个就相当于vue中的data,也是一样的。不过这个修改state,需要使用setState()方法,而且这个方法是异步的,有一个回调函数。
三、ReactDOM
react-dom 的 package 提供了可在应用顶层使用的 DOM(DOM-specific)方法。引入方法为
import ReactDOM from 'react-dom'
- (1)ReactDOM.render(element, container[, callback]): 这个方法在提供的 container 里渲染一个 React元素,并返回对该组件的引用(或者针对无状态组件返回 null)。把最顶层的组件,挂载到HTML页面上面去,就是用的这个方法
- 当首次调用时,容器节点里的所有 DOM 元素都会被替换,后续的调用则会使用 React 的 DOM 差分算法(DOM diffing algorithm)进行高效的更新
ReactDOM.render(
<Board />,
document.getElementById('root')
);
- (2)ReactDOM.hydrate(element, container[, callback]): 与 render() 相同,但它用于在 ReactDOMServer 渲染的容器中对 HTML 的内容进行 hydrate 操作
- (3)ReactDOM.unmountComponentAtNode(container): 从 DOM 中卸载组件,会将其事件处理器(event handlers)和 state 一并清除
- (4)ReactDOM.createPortal(child, container): 创建 portal。Portal 将提供一种将子节点渲染到 DOM 节点中的方式,该节点存在于 DOM 组件的层次结构之外
四、ReactDOMServer
ReactDOMServer 对象允许你将组件渲染成静态标记。通常,它被使用在 Node 服务端上
import ReactDOMServer from 'react-dom/server';
用在服务端的东西,就先不看了
五、DOM 元素
React 实现了一套独立于浏览器的 DOM 系统,兼顾了性能和跨浏览器的兼容性。真的服了,react里面的dom是它自己搞的,不是之前浏览器那个dom!!!
在 React 中,所有的 DOM 特性和属性(包括事件处理)都应该是小驼峰命名的方式。
- (1)checked: 表示表单是否被选中
- (2)selected: 组件支持 selected 属性。你可以使用该属性设置组件是否被选择
- (3)value: 用于受控组件,设置组件的value;另外还一个值为defaultValue 对应的是非受控组件的属性,用于设置组件第一次挂载时的 value。
- (4)className: 如html中的class,在react中要写为className。
- (5)htmlFor: 由于 for 在 JavaScript 中是保留字,所以 React 元素中使用了 htmlFor 来代替。这个主要是用在label标签上面的,
<label htmlFor="">
- (6)dangerouslySetInnerHTML: 这个为 React 为浏览器 DOM 提供 innerHTML 的替换方案
function createMarkup() {return {__html: 'First · Second'};}
function MyComponent() {return <div dangerouslySetInnerHTML={createMarkup()} />;}
- (7)onChange事件:这里这个onChange事件类似于原生的input事件,不是原生的onchange事件了;就是说每次只要输入框的字符发生变化的时候,就会触发这个事件
- (8)style: style 接受一个JavaScript 对象,对象的属性采用小驼峰命名(如果属性为浏览器引擎前缀,则应以大写字母开头),而不是 CSS 字符串。不过通常不推荐将 style 属性作为设置元素样式的主要方式,因为样式不会自动补齐前缀
<input readOnly={true} />
const divStyle = {color: 'blue',backgroundImage: 'url(' + imgUrl + ')',};
function HelloWorldComponent() {return <div style={divStyle}>Hello World!</div>;}
六、合成事件
本章记录了构成 React 事件系统一部分的 SyntheticEvent 包装器
- (1)剪贴板事件:
// 事件名 onCopy onCut onPaste
// 属性:DOMDataTransfer clipboardData
- (2)复合事件:
// 事件名 onCompositionEnd onCompositionStart onCompositionUpdate
// 属性:string data
- (3)键盘事件: key 属性可以是 DOM Level 3 Events spec 里记录的任意值
// 事件名 onKeyDown onKeyPress onKeyUp
// 属性:
boolean altKey/number charCode/boolean ctrlKey/boolean/getModifierState(key)/string key
number keyCode/string locale/number location/boolean metaKey/boolean/repeat/boolean shiftKey/number which
- (4)焦点事件: 这些焦点事件在 React DOM 上的所有元素都有效,不只是表单元素
// 事件名 onFocus onBlur
// 属性: DOMEventTarget relatedTarget
- (5)表单事件:
// 事件名 onChange onInput onInvalid onSubmit
- (6)Mouse Events: onMouseEnter 和 onMouseLeave 事件从离开的元素向进入的元素传播,不是正常的冒泡,也没有捕获阶段
// 事件名
onClick onContextMenu onDoubleClick onDrag onDragEnd onDragEnter onDragExit
onDragLeave onDragOver onDragStart onDrop onMouseDown onMouseEnter onMouseLeave
onMouseMove onMouseOut onMouseOver onMouseUp
// 属性:
boolean altKey/number button/number buttons/number clientX/number clientY/boolean ctrlKey/boolean getModifierState(key)
boolean metaKey/number pageX/number pageY/DOMEventTarget relatedTarget/number screenX/number screenY/boolean shiftKey
- (7)指针事件: onPointerEnter 和 onPointerLeave 事件从离开的元素向进入的元素传播,不是正常的冒泡,也没有捕获阶段
// 事件名
onPointerDown onPointerMove onPointerUp onPointerCancel onGotPointerCapture
onLostPointerCapture onPointerEnter onPointerLeave onPointerOver onPointerOut
// 属性:
number pointerId/number width/number height/number pressure/number tangentialPressure/number tiltX/number tiltY/number twist/string pointerType/boolean isPrimary
- (8)选择事件:
// 事件名 onSelect
- (9)触摸事件:
// 事件名 onTouchCancel onTouchEnd onTouchMove onTouchStart
// 属性:
boolean altKey/DOMTouchList changedTouches/boolean ctrlKey/boolean getModifierState(key)/boolean metaKey/boolean shiftKey/DOMTouchList targetTouches/DOMTouchList touches
- (10)UI 事件:
// 事件名 onScroll
// 属性:number detail/DOMAbstractView view
- (11)滚轮事件:
// 事件名 onWheel
// 属性:number deltaMode/number deltaX/number deltaY/number deltaZ
- (12)媒体事件:
// 事件名
onAbort onCanPlay onCanPlayThrough onDurationChange onEmptied onEncrypted
onEnded onError onLoadedData onLoadedMetadata onLoadStart onPause onPlay
onPlaying onProgress onRateChange onSeeked onSeeking onStalled onSuspend
onTimeUpdate onVolumeChange onWaiting
- (13)图像事件:
// 事件名 onLoad onError
- (14)动画事件:
// 事件名 onAnimationStart onAnimationEnd onAnimationIteration
// 属性:string animationName/string pseudoElement/float elapsedTime
- (15)过渡事件:
// 事件名 onTransitionEnd
// 属性:string propertyName/string pseudoElement/float elapsedTime
- (16)其他事件:
// 事件名 onToggle
七、Test Utilities
ReactTestUtils 可搭配你所选的测试框架,轻松实现 React 组件测试。在 Facebook 内部,我们使用 Jest 来轻松实现 JavaScript 测试。引入方式为
import ReactTestUtils from 'react-dom/test-utils';