【React Series】High-level components

This article is from the #React tutorial series: https://mp.weixin.qq.com/mp/appmsgalbum?__biz=Mzg5MDAzNzkwNA==&action=getalbum&album_id=1566025152667107329 )

1. High-order components

1.1. Understanding higher-order components

What are higher-order components? I believe many students have heard of and used higher-order functions. They are very similar, so we can first review what higher-order functions are.

Wikipedia definition of higher-order function : at least one of the following conditions is met:

  • Accepts one or more functions as input;
  • Output a function;

The more common ones in JavaScript filter、map、reduceare higher-order functions.

So what are higher-order components?

  • The English name for high-order components is Higher-Order Components , or HOC for short ;
  • Official definition: A higher-order component is a function whose parameters are components and whose return value is a new component ;

We can perform the following analysis:

  • First of all, a higher-order component itself is not a component , but a function ;
  • Secondly, the parameter of this function is a component , and the return value is also a component ;

The calling process of higher-order components is similar to this:

const EnhancedComponent = higherOrderComponent(WrappedComponent);

The writing process of higher-order functions is similar to this:

function higherOrderComponent(WrapperComponent) {
    
    
  return class NewComponent extends PureComponent {
    
    
    render() {
    
    
      return <WrapperComponent/>
    }
  }
}

Component name issue:

  • In ES6, the class name can be omitted in class expressions, so it can be written as follows:
function higherOrderComponent(WrapperComponent) {
    
    
  return class extends PureComponent {
    
    
    render() {
    
    
      return <WrapperComponent/>
    }
  }
}
  • In addition, the name of the component can be displayNamemodified through:
    Insert image description here
    The complete code can be written like this:
import React, {
    
     PureComponent } from 'react';

function higherOrderComponent(WrapperComponent) {
    
    
  return class NewComponent extends PureComponent {
    
    
    render() {
    
    
      return <WrapperComponent/>
    }
  }
}

class App extends PureComponent {
    
    
  render() {
    
    
    return (
      <div>
        App
      </div>
    )
  }
}

export default higherOrderComponent(App);

Higher-order components are not part of the React API. They are design patterns based on the composition features of React ;

Higher-order components are very common in some React third-party libraries:

  • For example, connect in redux;
  • For react-routerexample withRouter;

What can high-order components help us do in our development?

1.2. Use of higher-order components

1.2.1. Enhancement of props

Add new ones without modifying the original codeprops

Suppose we have the following case:

class Header extends PureComponent {
    
    
  render() {
    
    
    const {
    
     name, age } = this.props;
    return <h2>Header {
    
    name + age}</h2>
  }
}

export default class App extends PureComponent {
    
    
  render() {
    
    
    return (
      <div>
        <Header name="aaa" age={
    
    18} />
      </div>
    )
  }
}

We can use a higher-order component to allow users to enhance a component without destroying the original structure props:

function enhanceProps(WrapperCpn, otherProps) {
    
    
	return props => <WrapperCpn {
    
    ...props} {
    
    ...otherProps} />
}

const EnhanceHeader = enhanceProps(Header, {
    
    height: 1.88})
  • A bit like interceptor and java dynamic proxy

Use higher-order components to share Context properties

import React, {
    
     PureComponent, createContext } from 'react';

const UserContext = createContext({
    
    
  nickname: "默认",
  level: -1
})

function Header(props) {
    
    
  return (
    <UserContext.Consumer>
      {
    
    
        value => {
    
    
          const {
    
     nickname, level } = value;
          return <h2>Header {
    
    "昵称:" + nickname + "等级" + level}</h2>
        }
      }
    </UserContext.Consumer>
  )
}

function Footer(props) {
    
    
  return (
    <UserContext.Consumer>
      {
    
    
        value => {
    
    
          const {
    
     nickname, level } = value;
          return <h2>Footer {
    
    "昵称:" + nickname + "等级" + level}</h2>
        }
      }
    </UserContext.Consumer>
  )
}

const EnhanceHeader = enhanceProps(Header, {
    
     height: 1.88 })

export default class App extends PureComponent {
    
    
  render() {
    
    
    return (
      <div>
        <UserContext.Provider value={
    
    {
    
     nickname: "why", level: 90 }}>
          <Header />
          <Footer />
        </UserContext.Provider>
      </div>
    )
  }
}

Take advantage of higher-order components withUser:

import React, {
    
     PureComponent, createContext } from 'react';

const UserContext = createContext({
    
    
  nickname: "默认",
  level: -1
})

function withUser(WrapperCpn) {
    
    
  return props => {
    
    
    return (
      <UserContext.Consumer>
        {
    
    
          value => {
    
    
            return <WrapperCpn {
    
    ...props} {
    
    ...value}/>
          }
        }
      </UserContext.Consumer>
    )
  }
}

function Header(props) {
    
    
  const {
    
     nickname, level } = props;
  return <h2>Header {
    
    "昵称:" + nickname + "等级:" + level}</h2>
}


function Footer(props) {
    
    
  const {
    
     nickname, level } = props;
  return <h2>Footer {
    
    "昵称:" + nickname + "等级:" + level}</h2>
}

const UserHeader = withUser(Header);
const UserFooter = withUser(Footer);

export default class App extends PureComponent {
    
    
  render() {
    
    
    return (
      <div>
        <UserContext.Provider value={
    
    {
    
     nickname: "why", level: 90 }}>
          <UserHeader />
          <UserFooter />
        </UserContext.Provider>
      </div>
    )
  }
}

1.2.2. Use high-order components for authentication judgment

During development, we may encounter scenarios like this:

  • Some pages require the user to successfully log in before they can enter;
  • If the user fails to log in successfully, jump directly to the login page;

At this time, we can use high-order components to complete the authentication operation:

function LoginPage() {
    
    
  return <h2>LoginPage</h2>
}

function CartPage() {
    
    
  return <h2>CartPage</h2>
}

export default class App extends PureComponent {
    
    
  render() {
    
    
    return (
      <div>
        <CartPage/>
      </div>
    )
  }
}

Write high-level components for authentication:

function loginAuth(Page) {
    
    
  return props => {
    
    
    if (props.isLogin) {
    
    
      return <Page/>
    } else {
    
    
      return <LoginPage/>
    }
  }
}

The complete code is as follows:

import React, {
    
     PureComponent } from 'react';

function loginAuth(Page) {
    
    
  return props => {
    
    
    if (props.isLogin) {
    
    
      return <Page/>
    } else {
    
    
      return <LoginPage/>
    }
  }
}

function LoginPage() {
    
    
  return <h2>LoginPage</h2>
}

function CartPage() {
    
    
  return <h2>CartPage</h2>
}

const AuthCartPage = loginAuth(CartPage);

export default class App extends PureComponent {
    
    
  render() {
    
    
    return (
      <div>
        <AuthCartPage isLogin={
    
    true}/>
      </div>
    )
  }
}

1.2.3. Life cycle hijacking

import React, {
    
     PureComponent } from 'react';

class Home extends PureComponent {
    
    

  UNSAFE_componentWillMount() {
    
    
    this.begin = Date.now();
  }

  componentDidMount() {
    
    
    this.end = Date.now();
    const interval = this.end - this.begin;
    console.log(`Home渲染使用时间:${
      
      interval}`)
  }

  render() {
    
    
    return (
      <div>
        <h2>Home</h2>
        <p>我是home的元素,哈哈哈</p>
      </div>
    )
  }
}

class Detail extends PureComponent {
    
    
  UNSAFE_componentWillMount() {
    
    
    this.begin = Date.now();
  }

  componentDidMount() {
    
    
    this.end = Date.now();
    const interval = this.end - this.begin;
    console.log(`Detail渲染使用时间:${
      
      interval}`)
  }

  render() {
    
    
    return (
      <div>
        <h2>Detail</h2>
        <p>我是detail的元素,哈哈哈</p>
      </div>
    )
  }
}

export default class App extends PureComponent {
    
    
  render() {
    
    
    return (
      <div>
        <Home/>
        <Detail/>
      </div>
    )
  }
}

We can define higher-order components as follows:

function logRenderTime(WrapperCpn) {
    
    
  return class extends PureComponent {
    
    
    UNSAFE_componentWillMount() {
    
    
      this.begin = Date.now();
    }

    componentDidMount() {
    
    
      this.end = Date.now();
      const interval = this.end - this.begin;
      console.log(`Home渲染使用时间:${
      
      interval}`)
    }

    render() {
    
    
      return <WrapperCpn {
    
    ...this.props}/>
    }
  }
}

const LogHome = logRenderTime(Home);
const LogDetail = logRenderTime(Detail);

The complete code is as follows:

import React, {
    
     PureComponent } from 'react';

function logRenderTime(WrapperCpn) {
    
    
  return class extends PureComponent {
    
    
    UNSAFE_componentWillMount() {
    
    
      this.begin = Date.now();
    }

    componentDidMount() {
    
    
      this.end = Date.now();
      const interval = this.end - this.begin;
      console.log(`${
      
      WrapperCpn.name}渲染使用时间:${
      
      interval}`)
    }

    render() {
    
    
      return <WrapperCpn {
    
    ...this.props}/>
    }
  }
}

class Home extends PureComponent {
    
    
  render() {
    
    
    return (
      <div>
        <h2>Home</h2>
        <p>我是home的元素,哈哈哈</p>
      </div>
    )
  }
}


class Detail extends PureComponent {
    
    
  render() {
    
    
    return (
      <div>
        <h2>Detail</h2>
        <p>我是detail的元素,哈哈哈</p>
      </div>
    )
  }
}

const LogHome = logRenderTime(Home);
const LogDetail = logRenderTime(Detail);

export default class App extends PureComponent {
    
    
  render() {
    
    
    return (
      <div>
        <LogHome />
        <LogDetail />
      </div>
    )
  }
}

This way of writing is actually to extract common code for reuse .

1.3. The meaning of higher-order functions

We will find that using higher-order components can handle some React code more elegantly.

In fact, early React provided a way to reuse components mixin, but it is no longer recommended to use:

  • MixinMay be mutually dependent and coupled, which is not conducive to code maintenance
  • Methods in different ones Mixinmay conflict with each other
  • MixinVery often, components are perceptible and even have to be processed, which can cause snowballing complexity to the code.

Of course, HOC also has its own shortcomings:

  • HOC needs to be wrapped or nested on the original component. If HOC is used extensively , a lot of nesting will be generated, which makes debugging very difficult;
  • HOC can be hijacked propsand may cause conflicts if the agreement is not followed;

The emergence of Hooks is groundbreaking. It solves many problems that existed before React, such as thispointing problems, nesting complexity problems of HOC , etc.

Guess you like

Origin blog.csdn.net/lyabc123456/article/details/135344365