React Component Patterns

Github addresses welcome star

preface

In the process of preparing a technical presentation for a conference, I wanted to take a moment to share some of my insights into designing the React component pattern. The components are the core of React, and understanding them is important to designing a good project architecture.

The chart in the article was taken from a very good talk (by Michael Chan). I highly recommend watching his video

What is a component

According to the React website, components allow you to divide your UI into individual, reusable components, and you only need to think about how each component is built.

When you first run the NPM install the react, can get to the react locally source (path. / node_modules/react/umd/react. Development. Js), it can be seen as a major component, provide a series of interface. React components are similar to JavaScript functions in that they take an input called “props” and return React elements that describe (declare) the user interface. All you have to do is tell React what your UI looks like, and React will do the rest for you (keeping the DOM and data in sync) and render out the UI. This is why React is called a declarative library.

Declarative means that if you want to go somewhere and you choose a taxi, you just tell the driver where you want to go and the driver will take you there. The imperative, on the other hand, requires you to drive yourself to your destination.

Component of the API

So, when you download React, what apis do you get? There are five of them:

  • render
  • state
  • props
  • context
  • lifecycle events

While components provide a complete, easy-to-use API, it’s natural for some components to use part of the API and for others to use a different API. Components were generally classified as Stateful and stateless components. Stateful components usually use render, state and lifecycle Events. Stateless components usually use render, props and context.

Component design patterns

Common design patterns are:

  • Container components
  • Presentational components
  • Higher-order components
  • Render Callbacks

Container components

The container component interacts (communicates) with external data and then renders its corresponding child component, Jason Bonta

The container component is the data or logic layer, and you can use the stateful API mentioned above. Using life cycle hooks, you can connect directly to a state management store, such as Redux or Flux, and pass data and callbacks to its corresponding child components via props. The React element that is returned from the container component’s Render method is composed of multiple display children. In order to have access to all stateful apis, container components must declare components using ES6 classes, not functions.

Below, we declare a component called Greeting, which has state, a lifecycle hook componentDidMount(), and Render.

class Greeting extends React.Component {
  constructor() {
    super();
    this.state = {
      name: ""}; }componentDidMount() {
    // AJAX
    this.setState(() => {
      return {
        name: "William"}; }); }render() {
    return( <div> <h1>Hello! {this.state.name}</h1> </div> ); }}Copy the code

At this point, the component is a stateful component. To turn the Greeting component into a container component, you can split the user interface into presentation components, as described below.

Presentational components

A display component can use props, render, and context (stateless apis). It is essentially a stateless component that can be declared with functions:

const GreetingCard = (props) => {
  return (
    <div>
      <h1>Hello! {props.name}</h1>
    </div>
  )
}
Copy the code

The presentation component only accepts data and callbacks from props, which are generated by the container component or its parent component.


const GreetingCard = (props) => {
  return (
    <div>
      <h1>{props.name}</h1>
    </div>
  )
}

class Greeting extends React.Component {
  constructor() {
    super();
    this.state = {
      name: ""}; }componentDidMount() {
    // AJAX
    this.setState(() => {
      return {
        name: "William"}; }); }render() {
    return( <div> <GreetingCard name={this.state.name} /> </div> ); }}Copy the code

As you can see above, I moved the part of the UI presentation from Greeting to a functional stateless component. Of course, this is just a simple example, but this is basically how it works in more complex applications.

High order Component (HOC)

A higher-order component is a function that takes a component as an argument and returns a new component.

This is a powerful pattern for any component to reuse a component’s logic. Like react-router-V4 and Redux. In React-router-v4, using withRouter(), your component can inherit some methods from the React-router using props. In redux, too, the connect({})() method puts actions and reducer into components.

Here’s an example:

import {withRouter} from 'react-router-dom';

class App extends React.Component {
  constructor() {
    super();
    this.state = {path: ' '}}componentDidMount() {
    let pathName = this.props.location.pathname;
    this.setState(() => {
      return {
        path: pathName,
      }
    })
  }
  
  render() {
    return (
      <div>
        <h1>Hi! I'm being rendered at: {this.state.path}  ) } } export default withRouter(App);Copy the code

When exporting my component, I wrapped my component withRouter() with React-router-V4. Then in the life cycle of hook componentDidMount (), can use this. Props. The location. The values in the pathname to update the state. My component gets the react-router-V4 method via props. There are many other examples.

Render callbacks

Like HOC, Render Callbacks or Render props are also powerful patterns for sharing or reusing component logic. Although more developers tend to reuse logic via HOC, there are reasons and advantages to using Render Callbacks — a nice example of Michael Jackson’s “never write another HOC.” Key to this, Render Callbacks reduce namespace conflicts and better illustrate where the code logic is coming from.

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
    };
  }

  increment = () => {
    this.setState(prevState => {
      return {
        count: prevState.count + 1,
      };
    });
  };

  render() {
    return (
      <div onClick={this.increment}>{this.props.children(this.state)}</div>
    );
  }
}

class App extends React.Component {
  render() {
    return( <Counter> {state => ( <div> <h1>The count is: {state.count}</h1> </div> )} </Counter> ); }}Copy the code

We nested the this.props. Children method in the Count component’s Render and passed it this.state as an argument. In the App component, I’ve wrapped it around a Counter, so in the App you can get the data methods of the Counter and so on. {state => ()} is the render callback. I automatically get the state in Counter.

Thanks for reading

Comments and suggestions are welcome. These are my views on the React component design pattern!

Render props (props

There are also new hooks apis that are added to React V16.8.0. You can also use functions to implement stateful components

Finally, check out Dan, one of the React authors, on his blog, four Principles for Writing Resilient Components.

If there are any mistakes or irregularities, please be sure to correct them. Thank you very much!

reference

  1. Levelup.gitconnected.com/react-compo…
  2. reactjs.org/