5 things to note when writing React components using hooks

5 things to note when writing React components using hooks

Hook is a new feature added in React16.8. Although the React official documentation has explained the relevant concepts of React hooks, it is difficult to use hooks well just by reading the official documentation. It is easy to fall into traps and errors when writing hooks. This article summarizes 5 bad places.

01. Use useState when render is not required

In function components, we can use useState to manage state, which makes state management very simple, but it is also easy to be abused. Let's look at the easily overlooked areas through the following code samples.

Not recommended×

function ClickButton(props){
 const [count, setCount] = setState(0)
 const onClickCount = () => {
  setCount((c) => c + 1)
 }
 const onClickRequest = () => {
  apiCall(count)
 }
 
 return (
  <div>
   <button onClick={onClickCount}>Click</button>
   <button onClick={onClickRequest}>Submit</button>
  </div>
 )
}

The problem: Looking carefully at the code above, at first glance there is nothing wrong with it. Clicking the button updates count . But the problem lies here. Our return part does not use the count state, and each setCount will cause the component to be re-rendered once, which is not what we need. The extra rendering will make the page performance worse, so we can modify the code as follows:

Recommended√
If we simply want a variable that can be saved during the component declaration cycle, but the update of the variable does not require the component to be re-rendered, we can use useRef hook.

function ClickButton(props){
 const count = useRef(0)
 const onClickCount = () => {
  count.current++
 }
 const onClickRequest = () => {
  apiCall(count.current)
 }

 return (
  <div>
   <button onClick={onClickCount}>Click</button>
   <button onClick={onClickRequest}>Submit</button>
  </div>
 )
}

02. Use router.push instead of link

In React SPA applications, we use react-router to handle route jumps. We often write a button in the component and handle route jumps by clicking the button event, as shown in the following code:

Not recommended×

function ClickButton(props){
 const history = useHistory()
 const onClickGo = () => {
  history.push('/where-page')
 }
 return <button onClick={onClickGo}>Go to where</button>
}

The problem: Although the above code works, it does not meet the requirements of Accessibility. The button will not be recognized as a link by the screen reader. Therefore, we can transform the code as follows:

Recommended√

function ClickButton(props){
 return <Link to="/next-page">
  <span>Go to where</span>
 </Link>
}

03. Handle actions with useEffect

Sometimes, we just want to run some additional code after React updates the DOM. For example, sending network requests, manually changing DOM, and recording logs.

Not recommended×

function DataList({ onSuccess }) {
 const [loading, setLoading] = useState(false);
 const [error, setError] = useState(null);
 const [data, setData] = useState(null);

 const fetchData = () => {
  setLoading(true);
  callApi()
   .then((res) => setData(res))
   .catch((err) => setError(err))
   .finally(() => setLoading(false));
 };

 useEffect(() => {
  fetchData();
 }, []);

 useEffect(() => {
  if (!loading && !error && data) {
   onSuccess();
  }
 }, [loading, error, data, onSuccess]);

 return <div>Data: {data}</div>;
}

The problem: The above code uses two useEffect , the first one is used to request asynchronous data, and the second one is used to call the callback function. The execution of the second useEffect will be triggered only when the first asynchronous request data succeeds. However, we cannot fully guarantee that the dependencies of the second useEffect are completely controlled by the successful request data of the first useEffect . Therefore, we can transform the code as follows:

Recommended√

function DataList({ onSuccess }) {
 const [loading, setLoading] = useState(false);
 const [error, setError] = useState(null);
 const [data, setData] = useState(null);

 const fetchData = () => {
  setLoading(true);
  callApi()
   .then((res) => {
    setData(res)
    onSuccess()
    })
   .catch((err) => setError(err))
   .finally(() => setLoading(false));
 };

 useEffect(() => {
  fetchData();
 }, []);
 return <div>Data: {data}</div>;
}

04. Single Responsibility Component

When should you split a component into several smaller components? How to build component tree? All of these issues arise every day when using component-based frameworks. However, a common mistake when designing components is to combine two use cases into one component.

Not recommended×

function Header({ menuItems }) {
 return (
  <header>
   <HeaderInner menuItems={menuItems} />
  </header>
 );
}

function HeaderInner({ menuItems }) {
 return isMobile() ? <BurgerButton menuItems={menuItems} /> : <Tabs tabData={menuItems} />;
}

The Problem: With this approach, the HeaderInner component is trying to be two different things at once. Doing more than one thing at a time is not ideal. Additionally, it makes it more difficult to test or reuse the component elsewhere. Therefore, we can transform the code as follows:

Recommended√

Moving the condition up one level makes it easier to see the purpose of the components and that they only have one responsibility, being either <Tabs/> or <BurgerButton/> , rather than trying to be two different things at the same time.

function Header(props) {
 return (
  <header>
   {isMobile() ? <BurgerButton menuItems={menuItems} /> : <Tabs tabData={menuItems} />}
  </header>
 )
}

05. Single Responsibility useEffects

By comparing componentWillReceiveProps or componentDidUpdate methods, I realized the beauty of userEffect . However, if useEffect is not used properly, problems may occur.

Not recommended×

function Example(props) {
 const location = useLocation();
 const fetchData = () => {
  /* Calling the api */
 };

 const updateBreadcrumbs = () => {
  /* Updating the breadcrumbs */
 };

 useEffect(() => {
  fetchData();
  updateBreadcrumbs();
 }, [location.pathname]);

 return (
  <div>
   <BreadCrumbs />
  </div>
 );
}

The problem: useEffect above triggers two side effects at the same time, but not all of them are the side effects we need, so we can modify the code as follows:

Recommended√

Separate two side effects from one useEffect.

function Example(props) {
 const location = useLocation();

 const fetchData = () => {
  /* Calling the api */
 };

 const updateBreadcrumbs = () => {
  /* Updating the breadcrumbs */
 };

 useEffect(() => {
  fetchData();
  updateBreadcrumbs();
 }, [location.pathname]);

 return (
  <div>
   <BreadCrumbs />
  </div>
 );
}

refer to:

Five common mistakes writing react components (with hooks) in 2020

The above are the details of the five things you need to pay attention to when using hooks to write React components. For more information about hooks to write React components, please pay attention to other related articles on 123WORDPRESS.COM!

You may also be interested in:
  • React hooks pros and cons
  • React Hooks Common Use Scenarios (Summary)
  • React hooks introductory tutorial
  • Example code for developing h5 form page based on react hooks and zarm component library configuration
  • React uses Hooks to simplify state binding of controlled components
  • Master React's most exciting new feature this year - React Hooks in 30 minutes
  • Record a complete react hooks practice
  • In-depth understanding and use of React Hooks
  • How React Hooks Work

<<:  Detailed explanation of Nginx static service configuration (root and alias instructions)

>>:  MySQL 5.6.27 Installation Tutorial under Linux

Recommend

HTML input box optimization to improve user experience and ease of use

In order to improve user experience and ease of us...

How to build php7 with docker custom image

First, perform a simple Docker installation. To c...

Design Theory: Ten Tips for Content Presentation

<br /> Focusing on the three aspects of text...

Getting Started with MySQL - Concepts

1. What is it? MySQL is the most popular relation...

Basic notes on html and css (must read for front-end)

When I first came into contact with HTML, I alway...

Five guidelines to help you write maintainable CSS code

1. Add a comment block at the beginning of the sty...

How to implement remote automatic backup of MongoDB in Linux

Preface After reading the previous article about ...

How to implement the builder pattern in Javascript

Overview The builder pattern is a relatively simp...

Research on the problem of flip navigation with tilted mouse

In this article, we will analyze the production of...

Using CSS to implement image frame animation and curve motion

The basic principle of all animations is to displ...

Element-ui directly clicks on the cell in the table to edit

Table of contents Achieve results Implementation ...