2
头图

As React becomes more and more popular, so does the number of React developers, who also encounter various problems during the development process.

In this article, I will combine my actual work experience to summarize 11 common mistakes in React development to help you avoid some mistakes.

If you are just starting to use React, it is recommended that you take a good look at this article. If you have already used React to develop projects, it is also recommended that you check the gaps and fill in the gaps.

After reading this article, you will learn how to avoid these 11 React mistakes:

  1. When rendering the list, the key is not used
  2. Modify the state value directly by assignment
  3. Bind the state value directly to the value attribute of the input tag
  4. Use state directly after executing setState
  5. Infinite loop when using useState + useEffect
  6. Forgetting to clean up side effects in useEffect
  7. Incorrect use of boolean operators
  8. No component parameter type defined
  9. Pass a string as a value to the component
  10. No component name starting with a capital letter
  11. Incorrect event binding for element

1. When rendering the list, do not use the key

Problem Description

When we were just learning React, we would render a list according to the documentation, such as:

 const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) => <li>{number}</li>);

After rendering, the console will prompt a warning ⚠️ a key should be provided for list items .

Solution

You just need to follow the prompts and add the key attribute to each item:

 const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number, index) => <li key={index}>{number}</li>);

key Helps React to identify which elements have changed, such as been added or removed. So we need to set a unique key value for each element in the array.

Documentation introduction

React - Basic List Component

2. Modify the state value directly by assignment

Problem Description

In React, state cannot be directly assigned and modified, otherwise it will cause problems that are difficult to repair, so the following is written:

 updateState = () => {
  this.state.name = "Chris1993";
};

At this point, the editor will prompt a warning ⚠️:

 Do not mutate state directly. Use setState().

Solution

Class components can be modified by the setState() method, and function components can be modified by using useState() :

 // ClassComponent:use setState()
this.setState({ name: "Chris1993" });

// FunctionConponent:use useState()
const [name, setName] = useState("");
setName("Chris1993");

Documentation introduction

React - State and Lifecycle
React - Using the State Hook

3. Bind the state value directly to the value attribute of the input tag

Problem Description

When we directly bind the value of state as a parameter to the value attribute of the input tag, we will find that no matter what we enter in the input box, The content of the input box will not change.

 export default function App() {
  const [count, setCount] = useState(0);
  return <input type="text" value={count} />;
}

This is because we use the state variable with state as the default value to assign to the <input> of value , and in the functional component to modify the state only by useState Returned set Method modification. So the solution is also very simple, as long as you use the set method when modifying.

Solution

Only need to bind a onChange event for <input> 6a1c8cb73e8b870f89c2ba1be429a75a---, and modify it by calling setCount :

 export default function App() {
  const [count, setCount] = useState(0);
  const change = (val) => setCount(val.value);
  return <input type="text" value={count} onChange={change} />;
}

4. Use state directly after executing setState

Problem Description

When we modify the data through setState() and get the data immediately, the data will still be the old value:

 // init state data
this.state = { name: "Chris1993" };

// update state data
this.setState({ name: "Hello Chris1993!" });
console.log(this.state.name); // output: Chris1993

We might think that the input this.state.name should be Hello Chris1993! , but the result is Chris1993 .
This is because setState() is asynchronous. When setState() is executed, the real update operation will be put into the asynchronous queue for execution, and the code to be executed next ( console.log this line) is executed synchronously, so the printout state is not the latest value.

Solution

You only need to encapsulate the subsequent operation to be performed into a function as the second parameter of setState() , and the callback function will be executed after the update is completed.

 this.setState({ name: "Hello Chris1993!" }, () => {
  console.log(this.state.name); // output: Hello Chris1993!
});

The correct content is now output.

5. Infinite loop when using useState + useEffect

Problem Description

useEffect() useState()返回的set*()方法,并且没有设置---8a42022c84bcee8fe4b3207b15398214---第二个参数时, useEffect() Infinite loop:

 export default function App() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    setCount(count + 1);
  });
  return <div className="App">{count}</div>;
}

At this time, you can see that the data on the page keeps increasing, useEffect() is called infinitely and enters an infinite loop state.

Solution

useEffect() 3b25ea1d27297f189238b0d7cd212fc0---使用错误的问题, useEffect() 75fe5c2b4d68f2c93004d959033fe258---可以看做是类组件中componentDidMountcomponentDidUpdate componentWillUnmount A combination of these three life cycle functions.
useEffect(effect, deps) Receive 2 parameters:

  • effect Side effect function;
  • deps Array of dependencies.

When the deps array changes, the side effect function effect will be executed.
The modification method only needs to pass in the second parameter of useEffect() [] :

 export default function App() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    setCount(count + 1);
  }, []);
  return <div className="App">{count}</div>;
}

Explain in detail the 4 cases used by useEffect :

  • The second parameter is not passed : any status update will trigger the side effect function of useEffect .
 useEffect(() => {
  setCount(count + 1);
});
  • The second parameter is an empty array : a side effect function that is only triggered when mounting and unmounting useEffect .
 useEffect(() => {
  setCount(count + 1);
}, []);
  • The second parameter is a single-valued array : only when the value changes, the side-effect function of useEffect will be triggered.
 useEffect(() => {
  setCount(count + 1);
}, [name]);
  • The second parameter is a multi-valued array : the side-effect function of useEffect will be triggered only when the incoming value changes.
 useEffect(() => {
  setCount(count + 1);
}, [name, age]);

6. Forgetting to clean up side effects in useEffect

Problem Description

In class components, we often use componentWillUnmount() life cycle methods to clean up some side effects, such as timers, event monitoring, etc.

Solution

You can set a return function for the side effect function of useEffect() , which is similar to the role of the componentWillUnmount() life cycle method:

 useEffect(() => {
  // Other Code
  return () => clearInterval(id);
}, [name, age]);

Documentation introduction

React - Example Using Hooks

7. Incorrect use of boolean operators

Problem Description

In JSX/TSX syntax, we often control rendered elements through boolean values, and in many cases we will use the && operator to handle this logic:

 const count = 0;
const Comp = () => count && <h1>Chris1993</h1>;

We will naturally think that the page displays empty content at this time, but it actually displays the content of 0 on it.

Solution

The reason is because the falsy expression causes elements after && to be skipped, but returns the value of the falsy expression. So we try to write the judgment condition as complete as possible, without relying on the true or false of JavaScript's boolean value to compare:

 const count = 0;
const Comp = () => count > 0 && <h1>Chris1993</h1>;

The page will display empty content.

Documentation introduction

React - Inline If with Logical && Operator

8. The component parameter type is not defined

Problem Description

It is common for team development. If the components developed by each person do not have well-defined parameter types, it is easy for cooperating colleagues to not know how to use the components, which is very troublesome, such as:

 const UserInfo = (props) => {
  return (
    <div>
      {props.name} : {props.age}
    </div>
  );
};

Solution

Solutions are

  • Using TypeScript, define the component props type;
 // ClassComponent
interface AppProps {
  value: string;
}
interface AppState {
  count: number;
}

class App extends React.Component<AppProps, AppStore> {
  // ...
}

// FunctionComponent
interface AppProps {
  value?: string;
}
const App: React.FC<AppProps> = ({ value = "", children }) => {
  //...
};
  • Instead of using TypeScript, you can use propTypes define props type;
 const UserInfo = (props) => {
  return (
    <div>
      {props.name} : {props.age}
    </div>
  );
};

UserInfo.propTypes = {
  name: PropTypes.string.isRequired,
  age: PropTypes.number.isRequired,
};

9. Passing Strings as Values to Components

Problem Description

Since React also has a template syntax, which is very similar to HTML, it often happens that numbers are passed directly to components as props, resulting in unexpected values when judging:

 <MyComp count="99"></MyComp>

Passing --- props.count === 99 --- in the MyComp component will return false .

Solution

The correct way should be to use curly brackets to pass parameters:

 <MyComp count={99}></MyComp>

10. There is no component name that starts with a capital letter

Problem Description

For newbies, forgetting to start a component name with a capital letter is a common problem. Components starting with a lowercase letter in JSX/TSX are compiled into HTML elements, eg <div /> for HTML tags.

 class myComponent extends React.component {}

Solution

Just change the first letter to uppercase:

 class MyComponent extends React.component {}

Documentation introduction

React - Rendering a Component

11. Incorrect event binding for element

Problem Description

 import { Component } from "react";

export default class HelloComponent extends Component {
  constructor() {
    super();
    this.state = {
      name: "Chris1993",
    };
  }

  update() {
    this.setState({ name: "Hello Chris1993!" });
  }
  render() {
    return (
      <div>
        <button onClick={this.update}>update</button>
      </div>
    );
  }
}

When clicking the update button, the console will report an error:

 Cannot read properties of undefined (reading 'setState')

Solution

This is because this points to the problem, and the solutions are as follows:

  • bind in the constructor
 constructor() {
  super();
  this.state = {
    name: "Chris1993"
  };
  this.update = this.update.bind(this);
}
  • Use arrow functions
 update = () => {
  this.setState({ name: "Hello Chris1993!" });
};
  • Bind in the render function (not recommended, create a new function every time the component renders, affecting performance)
 <button onClick={this.update.bind(this)}>update</button>
  • Use arrow functions in the render function (not recommended, create a new function every time the component renders, affecting performance)
 <button onClick={() => this.update()}>update</button>

Documentation introduction

React - How do I pass an event handler (like onClick) to a component?

If you think this article is good, please like, comment and follow, your support is the biggest motivation for me to share.


pingan8787
3.2k 声望4.1k 粉丝

🌼 前端宝藏小哥哥