创建类组件
React.Component
React.Component 是使用 ES6 classes 方式定义 React 组件的基类:
class Greeting extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
React.PureComponent
React.PureComponent 与 React.Component 很相似。两者的区别在于 React.Component 并未实现 shouldComponentUpdate(),而 React.PureComponent 中以浅层对比 prop 和 state 的方式来实现了该函数。
如果赋予 React
组件相同的 props
和 state
,render()
函数会渲染相同的内容,那么在某些情况下使用 React.PureComponent
可提高性能。
React.memo
const MyComponent = React.memo(function MyComponent(props) {
/* 使用 props 渲染 */
});
React.memo 为高阶组件。
如果你的组件在相同 props 的情况下渲染相同的结果,那么你可以通过将其包装在 React.memo 中调用,以此通过记忆组件渲染结果的方式来提高组件的性能表现。这意味着在这种情况下,React 将跳过渲染组件的操作并直接复用最近一次渲染的结果。
React.memo 仅检查 props 变更。如果函数组件被 React.memo 包裹,且其实现中拥有 useState,useReducer 或 useContext 的 Hook,当 state 或 context 发生变化时,它仍会重新渲染。
默认情况下其只会对复杂对象做浅层对比,如果你想要控制对比过程,那么请将自定义的比较函数通过第二个参数传入来实现。
function MyComponent(props) {
/* 使用 props 渲染 */
}
function areEqual(prevProps, nextProps) {
/*
如果把 nextProps 传入 render 方法的返回结果与
将 prevProps 传入 render 方法的返回结果一致则返回 true,
否则返回 false
*/
}
export default React.memo(MyComponent, areEqual);
此方法仅作为性能优化的方式而存在。但请不要依赖它来“阻止”渲染,因为这会产生 bug。因为:还有其他方式导致组件重新渲染,不仅仅是props。
创建函数组件
一个普通的函数组件
function A(props: any, ref: ForwardedRef<HTMLHeadingElement>) {
return (
<AContext.Consumer>
{/* 子组件消费上下文的数据 */}
{value => <h1 ref={ref}>h1{value.a}</h1>}
</AContext.Consumer>
)
}
通过克隆得到一个组件
通过api方式克隆:React.cloneElement
- React.cloneElement( element, [config], […children] )
function A(props: any, ref: ForwardedRef<HTMLHeadingElement>) {
return (
<AContext.Consumer>
{/* 子组件消费上下文的数据 */}
{value => <h1 ref={ref}>h1{value.a}</h1>}
</AContext.Consumer>
)
}
const AC = React.cloneElement(<A />)
- React.cloneElement( element, [config], […children] )
通过jsx进行克隆
const AC = React.cloneElement(<App />)
const b = <A1.type {...A1.props} {...{ a: 1 }} />
这种克隆的方式是保留了App组件的ref。这意味着当通过 ref 获取子节点时,你将不会意外地从你祖先节点上窃取它。相同的 ref 将添加到克隆后的新元素中。如果存在新的 ref 或 key 将覆盖之前的。也就是说,如果原来的组件和新组件都被渲染了,那么ref的值就是原来组件绑定的ref的值。除非手动的覆盖ref的值。
其他方式创建react组件
React.forwardRef
React.forwardRef 会创建一个React组件,这个组件能够将其接受的 ref 属性转发到其组件树下的另一个组件中。这种技术并不常见,但在以下两种场景中特别有用:
- 在高阶组件中转发 refs
React.forwardRef 接受渲染函数作为参数。React 将使用 props 和 ref 作为参数来调用此函数。此函数应返回 React 节点。
懒加载 React.lazy
React.lazy() 允许你定义一个动态加载的组件。这有助于缩减 bundle 的体积,并延迟加载在初次渲染时未用到的组件。类似于Vue的懒加载组件。分包chunk
// 这个组件是动态加载的
const SomeComponent = React.lazy(() => import('./SomeComponent'));
React.lazy要配合React.Suspense进行使用。
React.Suspense
React.Suspense 可以指定加载指示器(loading indicator),以防其组件树中的某些子组件尚未具备渲染条件。目前,懒加载组件是
// 该组件是动态加载的
const OtherComponent = React.lazy(() => import('./OtherComponent'));
function MyComponent() {
return (
// 显示 <Spinner> 组件直至 OtherComponent 加载完成
<React.Suspense fallback={<Spinner />}>
<div>
<OtherComponent />
</div>
</React.Suspense>
);
}
ReactDom.createPortal
Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案。
返回值是一个react结点对象。可以用于渲染在页面中。
ReactDOM.createPortal(child, container)
这种方式可以将一个react结点渲染到页面中的任何元素下面。比如一些弹窗啊,动画,层级比较高的内容。