Three ways to share component logic in React

Three ways to share component logic in React

Without further ado, these three methods are: render props, higher-order components, and custom Hooks. The following demonstrates

Suppose there is a TimeOnPage component dedicated to recording the time a user stays on the current page, like this:

const TimeOnPage = () => {
 const [second, setSecond] = useState(0);

 useEffect(() => {
  setTimeout(() => {
   setSecond(second + 1);
  }, 1000);
 }, [second]);
 return (
  <div>Dwell time: {second} seconds</div>
 );
}

If another component needs to reuse this functionality, can we encapsulate it so it can be easily shared with other components?

It is natural to think of nested subcomponents and use props to pass parameters.

const Child = (props) => {
 return <div>stayTime: {props.stayTime}s</div>;
};

const TimeOnPage = () => {
 const [second, setSecond] = useState(0);

 useEffect(() => {
  setTimeout(() => {
   setSecond(second + 1);
  }, 1000);
 }, [second]);
 return (
  <div>
   <Child stayTime={second} />
  </div>
 );
}

This is hard-coded inside the TimeOnPage component and has not yet achieved the goal of encapsulation and reuse. See how render props works?

Render props

"render prop" refers to a simple technique for sharing code between React components using a prop whose value is a function.

Continuing from the previous article, define a prop with a function value in TimeOnPage. If you want to render a component, just return it in the function. The function parameter is the state you want to share.

const Child = (props) => {
 return <div>stayTime: {props.stayTime}s</div>;
};

const TimeOnPage = (props) => {
 const [second, setSecond] = useState(0);

 useEffect(() => {
  setTimeout(() => {
   setSecond(second + 1);
  }, 1000);
 }, [second]);
 return <div>{props.render(second)}</div>;
};

<TimeOnPage render={(stayTime) => <Child stayTime={stayTime} />

In fact, render prop is a function prop used to tell the component what content needs to be rendered.
React Router also uses this technique.

<Router>
 <Route path="/home" render={() => <div>Home</div>} />
</Router>

Higher-order components

Higher-order components (HOC) are an advanced technique for reusing component logic in React. HOC itself is not part of the React API, it is a design pattern based on the composition characteristics of React.

A high-order component is a function whose parameter is a component A that needs to be reused and whose return value is a new component N. The new component N is processed based on component A, but component A itself will not be modified, only the function is enhanced.

Suppose there is a news list component that looks like this:

const NewList = () => {
 return (
  <div>
   <ul>
    <li>news item</li>
    <li>news item</li>
   </ul>
  </div>
 );
}

If you want to display the loading animation component <Loading /> during the loading of the news list, you usually do this

const Loading = () => {
 // loading animation}
const NewList = ({ isLoading }) => {
 return isLoading ? (
  <Loading />
 ) : (
  <div>
   <ul>
    <li>news item</li>
    <li>news item</li>
   </ul>
  </div>
 );
};

Suppose now the Table component also wants to display the loading animation component during data loading, following a similar pattern

const Loading = () => {
 // loading animation}
const DataList = ({ isLoading, ...props }) => {
 return isLoading ? (
  <Loading />
 ) : (
  <Table {...props} />
 );
};

From the above, you will find that the structures of DataList and NewList are extremely similar. If there are third and fourth components to be loaded, do we continue to repeat this pattern for the third and fourth time? This is not the most ideal approach. A better approach is to use a higher-order component to abstract this pattern:

const WithLoading = (WrappedComponent) => {
 return ({isLoading, ...props}) => {
  return isLoading ? <Loading /> : <WrappedComponent {...props} />;
 }
};

Then you can add loading to them separately without modifying NewList and DataList

const NewList = () => {
 return (
  <div>
   <ul>
    <li>news item</li>
    <li>news item</li>
   </ul>
  </div>
 );
};

const DataList = (props) => {
 return <Table {...props} />
};

const WithLoading = (WrappedComponent) => {
 return ({isLoading, ...props}) => {
  return isLoading ? <Loading /> : <WrappedComponent {...props} />;
 }
};
// NewList with loading
const WithLoadingNewList = WithLoading(<NewList />)
// DataList with loading
const WithLoadingDataList = WithLoading(<DataList />)

Custom Hooks

Hooks are a new feature in React 16.8. It allows you to use state and other React features without writing classes.

React Hooks include useState, useEffect, etc. They are all functions. Custom Hook is also a function. Its name also starts with use. Other Hooks can be called inside the function. Unlike React components, custom Hooks do not have to return a value. Unlike ordinary functions, custom Hooks can call other Hooks, while ordinary functions cannot.

When writing business logic, some reusable methods are generally defined as tool functions, which can then be reused everywhere. Similarly, by customizing Hooks, you can extract component logic into reusable functions. Whether to choose a custom Hook or a tool function depends on whether the component logic to be extracted requires other Hooks. If so, choose a custom Hook, otherwise just use a tool function.

Go back to the first TimeOnPage component in this article and change it to a custom Hook

const useTimeOnPage = () => {
 const [second, setSecond] = useState(0);

 useEffect(() => {
  setTimeout(() => {
   setSecond(second + 1);
  }, 1000);
 }, [second]);
 return second;
}

How to use

const Demo = () => {
 const stayTime = useTimeOnPage();
 return <div>Current page stay time: {stayTime} seconds</div>
}

Summarize

The three ways of sharing component logic have their own applicable scenarios:
Render props are suitable for sharing parent components with different subcomponents/sub-elements. The "pits" of subcomponents/sub-elements have been defined and can only be rendered in the specified positions;
High-order components are suitable for extending components without modifying the original components;
Pure functions can basically do what custom Hooks can do, but sometimes it is more convenient and faster to use custom Hooks.
Link to this article: Github

This concludes this article on the three ways to share component logic in React. For more content about React shared component logic, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope you will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • React component refactoring: nesting + inheritance and high-order components explained
  • The communication process between nested components and nested components in React
  • Tips for writing concise React components
  • 5 things to note when writing React components using hooks
  • React implements the sample code of Radio component
  • Detailed explanation of how to implement login function by combining React with Antd's Form component
  • Example code for developing h5 form page based on react hooks and zarm component library configuration
  • React antd tabs switching causes repeated refresh of subcomponents
  • How to pass pop-up form content to parent component in react-antd
  • Use antd's form component in the react project to dynamically set the value of the input box
  • A brief talk about component logic reuse in React
  • React nested component construction order

<<:  MySQL 5.7.17 installation graphic tutorial (windows)

>>:  Detailed tutorial on installing PHP and Nginx on Centos7

Recommend

Summary of two methods to implement vue printing function

Method 1: Install the plugin via npm 1. Install n...

MySQL Series Database Design Three Paradigm Tutorial Examples

Table of contents 1. Knowledge description of the...

WeChat applet scroll-view realizes left and right linkage

This article shares the specific code for WeChat ...

Example of using UserMap in IMG

usemap is an attribute of the <img> tag, use...

CSS to achieve fast and cool shaking animation effect

1. Introduction to Animate.css Animate.css is a r...

Node uses async_hooks module for request tracking

The async_hooks module is an experimental API off...

Uninstalling MySQL database under Linux

How to uninstall MySQL database under Linux? The ...

How to start and stop SpringBoot jar program deployment shell script in Linux

Without further ado, let me give you the code. Th...

WeChat applet custom tabbar component

This article shares the specific code of the WeCh...

How to solve the phantom read problem in MySQL

Table of contents Preface 1. What is phantom read...

CentOS 7.6 installation of MySQL 5.7 GA version tutorial diagram

Table of contents Environment Preparation Environ...

MySQL service and database management

Table of contents 1. Start and stop service instr...