Master React Design Patterns (render prop & HOC)

List Of Content

ADS Area (CARBON)

ADS Area (CARBON)

 

What is a Design Pattern

A Design Pattern is a general repeatable solution to a commonly occurring problem in software design.

In React it is mostly to solve an issue regarding rendering and passing props with ease.

React has a lot of awesome design patterns that help you as a developer to solve common issues and rendering problems when building React apps.

Render Prop

The term "render prop" refers to a technique for sharing code between React components using prop whose value is function. -React Docs

render prop is For Component that needs to share state with other encapsulated components without creating a different component.

Let's say you have a Form component that encapsulates the form behaviour by managing input values in the state and does the validation behind the scenes so you could have re-usable Form components and easy API to work with.

import React from "react";

export function Form(props) {
  const { onSubmit } = props

  const [values, setValues] = useState({})

  const handleSubmit = () => {
    //Run Form Specific OnSubmit Handler
    onSubmit(values)

    //TODO: CLEAR THE FORM AFTER SUBMIT
  }

  return (
    <form onSubmit={handleSubmit} onChange={}>
      {props.children}
    </form>
  )
}

The Form component manages the input values on the state and provides it onSubmit so every time the form is submitted the onSubmit callback going to receive the input values so it could send an API request or anything concerning the form data.

The only limitation is we can't have controlled inputs when rendering inside the Form component since we can get the values off the Form component in while rendering.

import React from "react";
import Form from "./form";

export function App(props) {
  return <div>
    <h3>Please Fill the Form</h3>
    return <Form>
      <InputGroup label="Username">
        <input value={"We cant get values off Form!"} />
      </InputGroup>
    </Form>  
  </div>  
}

The can't set the username input value since we can't get the values off the Form component.

That's where "render prop" pattern comes in handy. To get the values and other props from Form component to use it while rendering we can pass-in a callback that takes those props as an argument and returns children to render.

If we use "render prop" pattern we need to change the Components as following.

import React from "react";
//"render prop" or "child as function"
export function Form(props) {
  const { onSubmit } = props

  const [values, setValues] = useState({})

  const handleSubmit = () => {
    //Run Form Specific OnSubmit Handler
    onSubmit(values)

    //TODO: CLEAR THE FORM AFTER SUBMIT
  }

  return (
    <form onSubmit={handleSubmit} onChange={}>
      {props.children({values})}
    </form>
  )
}

The only change we did on the Form component is instead of rendering children as an array of components we rendering it as a function that takes the props, in this case, it is only an object of Form values.

and this is the simple trick for the "render prop" pattern. You can use other prop names like render to provide render prop callback for rendering, we used children in this case because it is more convenient to directly render children in an encapsulated Form Component.

For using the new Form component is simply by rendering a callback function as a child that takes the passed props object as argument and returns the children desired to be rendered between <Form></Form>.

import React from "react";
import Form from "./form";

export function App(props) {
  return <div>
    <h3>Please Fill the Form</h3>
    return <Form>
    {({ values })} => (
      <InputGroup label="Username">
        <input value={values.username} />
      </InputGroup>
    )
    </Form>  
  </div>  
}

If you can observe that the username input now it can take the values and get the current username value off Form so it could work in a controlled mode.

This pattern can be used in a lot of other case scenarios where you need to expose a Parent component's state into children in render-time.

NOTE: You can use any prop function for ex "render" to provide render prop pattern and pass a callback function. We only used children in this case cause it makes more sence in a Form component.

Higher-Order Component (HOC)

(HOC) is for reusing component logic. They are a pattern that emerges from React's compositional nature. -React Docs.

ComponentWithLogic = higherOrderComponent(WrappedComponent);

The main idea behind HOC is for reusing same logic for custom components. It takes a base component as an argument and returns a new Component with applied logic.

It helps a lot for reusing the same logic for multiple components.

To see what HOC are and how you can use them we can create a simple Clickable component that renders a clickable button which takes a text and onClick props.

import React from "react";

export function Clickable(props) {
  return <Button onClick={props.onClick}>
    {props.text}
  </Button>
}

You can provide a custom callback to execute upon button click.

Let's say we created other components built on top of this Clickable Component that abstract the same functionality with added features and we needed to make this Clickable component as Toggleable.

It may seem easy to just re-create the component as Toggleable components and that is it. Well, not really cause that will require you to re-create all components and this is not a good approach.

That's where Higher Order Component pattern comes in handy it will allow us to create a factory-like function which every time we give it a Clickable component it returns a new component with the Toggleable functionality.

HOC always returns a new Component with applied logic.

Let's create makeToggleable HOC for generating Toggleable from Clickable Components.

 

import React from "react";

//Make a clickable component toggleable
export function makeToggleable(Clickable) {

  return class extends React.Component {

    constructor() {
      super();
      this.toggle = this.toggle.bind(this);
      this.state = {
        show: false
      };
    }

    toggle() {
      this.setState(prevState => ({ show: !prevState.show }));
    }

    render() {
      return (
        <div>
          <Clickable {...this.props} onClick={this.toggle} />
          {this.state.show && this.props.children}
        </div> 
      )
    }
  }
}

makeToggleable is a function that takes the base component and returns a new Class Component which represents the new component with the wrapped Clickable component.

The HOC component can take props as normal component and manage state which in this case is being used for keeping track of the toggle state either show or hide, with a provided toggle method for toggling the state between show and hide.

At the render method, we render the wrapped clickable component with toggle state either show or hide the provided children so we can simulate the toggle.

HOC have more benifitial side when building Frameworks or Libraries cause it easily allow you to encapsulate the logical 

 

Share Tutorial

Made With By

Ipenywis Founder, Game/Web Developer, Love Play Games