开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情
什么是React Api reference?就是React顶层Api。我们都知道jsx其实就是React.createElment的语法糖,React.createElement就属于React顶层Api。
React.Component()
React的类组件都继承自React.Compoent,比如类组件的render()方法,setState()方法,生命周期等都是在React.Component这个父类中实现的。
import { Component } from 'react'
export class index extends Component {
static propTypes = {
second: third
}
render() {
return (
<div>index</div>
)
}
}
React.PureComponent()
从命名上我们可以看出这个方法是创建一个纯组件,我们知道在类组件中使用shouldComponentUpdate()方法可以控制组件是否更新渲染。然而PureComponent自己就“帮”我们使用了该方法,当props或者state浅对比没有更改的时候,就不会渲染更新视图。
import { Component, PureComponent } from 'react'
export default class index extends Component {
constructor() {
super()
}
render() {
return (
<div>
<Pure></Pure>
<Com></Com>
</div>
)
}
}
class Pure extends PureComponent {
constructor() {
super()
this.state = {
name: 'pure'
}
}
changeHandler = () => {
this.setState({
name: 'pure'
})
}
componentDidUpdate() {
console.log('pure componentDidUpdate')
}
render() {
console.log('render pure')
return (
<div>
<p>我是纯组件{this.state.name}</p>
{/* 点击按钮不会触发componentDidUpdate 和render 因为state并没有修改 */}
<button onClick={() => this.changeHandler()}>修改state</button>
</div>
)
}
}
class Com extends Component {
constructor() {
super()
this.state = {
name: 'component'
}
}
componentDidUpdate() {
console.log('com componentDidUpdate')
}
changeHandler = () => {
this.setState({
name: 'component'
})
}
render() {
console.log('render com')
return (
<div>
<p>我是一般组件{this.state.name}</p>
{/* 点击按钮会触发componentDidUpdate 和render 即使state并没有修改 */}
<button onClick={() => this.changeHandler()}>修改state</button>
</div>
)
}
}
React.memo()
这是一个高阶组件,但是它用于在函数组件上。当你的组件接受相同的props时,不需要更新渲染,就可以使用React.memo把这个组件包裹起来。React.memo仅检查props变更。
import {useState, memo} from 'react';
export default function App() {
const [first, setfirst] = useState('first')
return (
<div>
{/* 点击按钮并不会触发MemoChild1再次渲染,因为props并未修改 */}
<button onClick={() => setfirst('haha')}>改变父亲</button>
<MemoChild1></MemoChild1>
<Child2></Child2>
</div>
)
}
const MemoChild1 = memo(function Child1() {
console.log('child1')
return (
<div>123</div>
)
})
function Child2() {
console.log('child2')
return (
<div>321</div>
)
}
React.memo还可以传入第二个参数,如果你想要控制对比过程,那么可以将自定义的比较函数通过第二个参数传入来实现。
const MemoChild1 = memo(function Child1() {
console.log('child1')
return (
<div>123</div>
)
}, (prevProps, nextProps) => {
// 如果之前传入的props.first值为first 则不“记忆”该组件,返回true则“记忆”该组件
if(prevProps.first === 'first') {
return false
} else {
return true
}
})
React.createElement()
React.createElement(
type,
[props],
[...children]
)
创建并返回指定类型的新React元素,类型参数既可以是字符串也可以是React组件。JSX则是该方法的语法糖。
React.cloneElement()
React.cloneElement(
element,
[config],
[...children]
)
以element元素为样板克隆并返回新的 React 元素。config中可包含新的props,key或ref。得到的元素的props是样板组件的props和config里面的props的浅合并结果。新元素的子元素取代样板元素的子元素。
React.isValidElement()
用于判断一个对象是否是React元素,返回true或false。
React.Children
React.Children为操作this.children.props这个数据结构提供了一些工具方法。
React.children.map(this.props.children, (item) => {
return <div>{item}</div>
})
React.Fragment
创建react组件的话需要一个根元素,但是根元素其实是多余的,所以我们可以使用<React.Fragment></React.Fragment>来充当这个根元素,并且它不会渲染出DOM元素,其简单写法为<></>
React.createRef()
创建一个可通过ref属性附加到React元素上的ref
import React from 'react'
export default class MyComponent extends React.Component {
constructor(props) {
super(props);
this.divRef = React.createRef();
this.ComRef = React.createRef();
}
render() {
return (
<>
<div ref={this.divRef}></div>
<List ref={this.ComRef}></List>
</>
)
}
componentDidMount() {
// 对该节点的引用在ref的current属性中
// 当原生HTML使用ref属性的时候,React.createRef()创建的ref对象的current属性就是所对应的原生DOM元素
console.log('原生dom节点:', this.divRef.current);
// 当react组件使用ref属性的时候,React.createRef()创建的ref对象的current属性就是组件的挂载实例
console.log('react组件:', this.ComRef.current);
}
}
class List extends React.Component {
render() {
return (
<div>list</div>
)
}
}
React.forwardRef()
如果在函数组件上面使用React.createRef(),这个时候控制台会报错,因为默认情况下,函数组件是没有实例的,就需要使用React.forwardRef()(可与 useImperativeHandle 结合使用)转发ref。
在应用组件中来说ref转发不常用,但是在可重用的组件库中这是很有用的。(ref不像props作为参数可以传递,所以如果要想传递ref就得用forwardRef)
React.forwardRef()的返回值是react组件,接受一个render函数。
import React from 'react'
export default class MyComponent extends React.Component {
constructor(props) {
super(props);
this.divRef = React.createRef();
this.ComRef = React.createRef();
}
render() {
return (
<>
<div ref={this.divRef}></div>
<FancyDiv ref={this.ComRef}></FancyDiv>
</>
)
}
componentDidMount() {
console.log('拿到传进去的ref:', this.ComRef.current);
}
}
// 让函数组件可以拥有ref属性
const FancyDiv = React.forwardRef((props, ref) => (
<div>
<span>123</span>
<p ref={ref}>321</p>
</div>
));
结合useImperativeHandle使用,父组件可使用子组件的方法
import React, { useImperativeHandle } from 'react'
export default class MyComponent extends React.Component {
constructor(props) {
super(props);
this.divRef = React.createRef();
this.ComRef = React.createRef();
}
clickHandler = () => {
this.ComRef.current.logSon();
}
render() {
return (
<>
<div ref={this.divRef}></div>
<FancyDiv ref={this.ComRef}></FancyDiv>
<button onClick={() => this.clickHandler()}>触发子组件的方法</button>
</>
)
}
componentDidMount() {
console.log('拿到传进去的ref:', this.ComRef.current);
}
}
const FancyDiv = React.forwardRef((props, ref) => {
// ref表示需要转发的ref,第二个参数返回的对象就是要传给父组件的属性和方法,第三个参数是依赖项,如果函数中有使用变量,则都需要写到第三个参数中,如果没有则可忽略
useImperativeHandle(ref, () => {
return {
logSon: () => {
console.log('测试');
}
}
},[])
return (
<div>
<span>123</span>
<p ref={ref}>321</p>
</div>
)
});
React.lazy
用于动态加载组件,有助于缩减bundle的体积,该组件的使用依赖于React.Suspense组件。
// index.js
import { useState } from 'react';
import Tab from '../../components/Tab'
export default function App() {
const [first, setfirst] = useState(false)
return (
<div>
{first && <Tab></Tab>}
<button onClick={() => setfirst(true)}>按钮1</button>
</div>
)
}
// tab.js
export default () => {
return(
<div>wo shi tab</div>
)
}
当我们直接引入组件,页面加载完毕,此时页面还不满足出现tab组件的条件,但是bundle里面已经有tab组件的代码了
我们再来看看使用React.lazy的效果
import {useState, Suspense, lazy} from 'react';
const Tab = lazy(() => import('../../components/Tab'));
export default function App() {
const [first, setfirst] = useState(false)
return (
<div>
{/* 当点击按钮的时候 才会加载tab组件的代码 */}
<button onClick={() => setfirst(true)}>按钮1</button>
<Suspense>
<div>
{first && <Tab />}
</div>
</Suspense>
</div>
)
}
我们可以看到这个时候bundle里面并没有tab组件的代码,然后我们点击按钮,让tab组件出现
这个时候会发现引入了一个src_components_Tab_index_js.chunk.js的js,这个js的内容就是tab组件了
React.Suspense
React.Suspense可以指定加载指示器。
// <Spinner />组件为一个loading组件 <Spinner />组件会一直显示直到<Tab>组件加载完毕
<React.Suspense fallback={<Spinner />}>
<div>
<Tab />
</div>
</React.Suspense>