创建类组件

React.Component

React.Component 是使用 ES6 classes 方式定义 React 组件的基类:

  1. class Greeting extends React.Component {
  2. render() {
  3. return <h1>Hello, {this.props.name}</h1>;
  4. }
  5. }

React.PureComponent

React.PureComponent 与 React.Component 很相似。两者的区别在于 React.Component 并未实现 shouldComponentUpdate(),而 React.PureComponent 中以浅层对比 prop 和 state 的方式来实现了该函数。
如果赋予 React 组件相同的 propsstaterender() 函数会渲染相同的内容,那么在某些情况下使用 React.PureComponent 可提高性能。

React.memo

  1. const MyComponent = React.memo(function MyComponent(props) {
  2. /* 使用 props 渲染 */
  3. });

React.memo 为高阶组件
如果你的组件在相同 props 的情况下渲染相同的结果,那么你可以通过将其包装在 React.memo 中调用,以此通过记忆组件渲染结果的方式来提高组件的性能表现。这意味着在这种情况下,React 将跳过渲染组件的操作并直接复用最近一次渲染的结果。

React.memo 仅检查 props 变更。如果函数组件被 React.memo 包裹,且其实现中拥有 useStateuseReduceruseContext 的 Hook,当 state 或 context 发生变化时,它仍会重新渲染。

默认情况下其只会对复杂对象做浅层对比,如果你想要控制对比过程,那么请将自定义的比较函数通过第二个参数传入来实现。

  1. function MyComponent(props) {
  2. /* 使用 props 渲染 */
  3. }
  4. function areEqual(prevProps, nextProps) {
  5. /*
  6. 如果把 nextProps 传入 render 方法的返回结果与
  7. 将 prevProps 传入 render 方法的返回结果一致则返回 true,
  8. 否则返回 false
  9. */
  10. }
  11. export default React.memo(MyComponent, areEqual);

此方法仅作为性能优化的方式而存在。但请不要依赖它来“阻止”渲染,因为这会产生 bug。因为:还有其他方式导致组件重新渲染,不仅仅是props。

创建函数组件

一个普通的函数组件

  1. function A(props: any, ref: ForwardedRef<HTMLHeadingElement>) {
  2. return (
  3. <AContext.Consumer>
  4. {/* 子组件消费上下文的数据 */}
  5. {value => <h1 ref={ref}>h1{value.a}</h1>}
  6. </AContext.Consumer>
  7. )
  8. }

通过克隆得到一个组件

  • 通过api方式克隆:React.cloneElement

    • React.cloneElement( element, [config], […children] )
      1. function A(props: any, ref: ForwardedRef<HTMLHeadingElement>) {
      2. return (
      3. <AContext.Consumer>
      4. {/* 子组件消费上下文的数据 */}
      5. {value => <h1 ref={ref}>h1{value.a}</h1>}
      6. </AContext.Consumer>
      7. )
      8. }
      9. const AC = React.cloneElement(<A />)
  • 通过jsx进行克隆

    1. const AC = React.cloneElement(<App />)
    2. 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 到 DOM 组件

  • 在高阶组件中转发 refs

React.forwardRef 接受渲染函数作为参数。React 将使用 props 和 ref 作为参数来调用此函数。此函数应返回 React 节点。

懒加载 React.lazy

React.lazy() 允许你定义一个动态加载的组件。这有助于缩减 bundle 的体积,并延迟加载在初次渲染时未用到的组件。类似于Vue的懒加载组件。分包chunk

  1. // 这个组件是动态加载的
  2. const SomeComponent = React.lazy(() => import('./SomeComponent'));

React.lazy要配合React.Suspense进行使用。

React.Suspense

React.Suspense 可以指定加载指示器(loading indicator),以防其组件树中的某些子组件尚未具备渲染条件。目前,懒加载组件是 支持的唯一用例:

  1. // 该组件是动态加载的
  2. const OtherComponent = React.lazy(() => import('./OtherComponent'));
  3. function MyComponent() {
  4. return (
  5. // 显示 <Spinner> 组件直至 OtherComponent 加载完成
  6. <React.Suspense fallback={<Spinner />}>
  7. <div>
  8. <OtherComponent />
  9. </div>
  10. </React.Suspense>
  11. );
  12. }

ReactDom.createPortal

Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案。
返回值是一个react结点对象。可以用于渲染在页面中。

  1. ReactDOM.createPortal(child, container)

这种方式可以将一个react结点渲染到页面中的任何元素下面。比如一些弹窗啊,动画,层级比较高的内容。