DEV Community

Cover image for Common Mistakes Developers Make When Using React and How to Avoid Them
Raji moshood
Raji moshood

Posted on

Common Mistakes Developers Make When Using React and How to Avoid Them

React is one of the most popular JavaScript libraries for building modern web applications. But even experienced developers make mistakes that can lead to performance issues, unexpected bugs, and poor user experience. In this guide, we’ll cover the most common mistakes developers make when using React—and how to avoid them like a pro.

  1. Mutating State Directly

❌ The Mistake:

Modifying state directly instead of using setState or the state setter function in hooks.

const [count, setCount] = useState(0);

// Incorrect ❌
count = count + 1;

Enter fullscreen mode Exit fullscreen mode

✅ The Solution:

Always use the state updater function to ensure React re-renders properly.

setCount(count + 1);

Enter fullscreen mode Exit fullscreen mode

Or if using previous state:

setCount(prevCount => prevCount + 1);

Enter fullscreen mode Exit fullscreen mode
  1. Using useEffect Incorrectly

❌ The Mistake:

Forgetting the dependency array (causing infinite re-renders).

Adding too many dependencies (causing unnecessary renders).

useEffect(() => {
  console.log("Runs on every render!"); // Infinite loop risk
});
Enter fullscreen mode Exit fullscreen mode

✅ The Solution:

Use an empty dependency array [] to run the effect only once.

Only include necessary dependencies.

useEffect(() => {
  console.log("Runs only once when the component mounts!");
}, []);

Enter fullscreen mode Exit fullscreen mode

For fetching data:

useEffect(() => {
  fetchData();
}, [someDependency]); // Runs only when someDependency changes
Enter fullscreen mode Exit fullscreen mode
  1. Not Using Keys in Lists

❌ The Mistake:

Using array indexes as keys, which can cause incorrect reordering.

const items = ["Apple", "Banana", "Cherry"];

{items.map((item, index) => (
  <li key={index}>{item}</li> // ❌ Bad practice
))}
Enter fullscreen mode Exit fullscreen mode

✅ The Solution:

Use unique and stable IDs as keys.

const items = [{ id: 1, name: "Apple" }, { id: 2, name: "Banana" }];

{items.map(item => (
  <li key={item.id}>{item.name}</li> // ✅ Good practice
))}
Enter fullscreen mode Exit fullscreen mode
  1. Not Handling Asynchronous State Updates Properly

❌ The Mistake:

React batches state updates, so reading state immediately after updating it may give outdated values.

const [count, setCount] = useState(0);

const handleClick = () => {
  setCount(count + 1);
  console.log(count); // ❌ This logs the old value
};
Enter fullscreen mode Exit fullscreen mode

✅ The Solution:

Use the functional updater to ensure correct values.

setCount(prevCount => prevCount + 1);
Enter fullscreen mode Exit fullscreen mode

Now, prevCount always holds the latest state value.

  1. Not Optimizing Performance with useMemo and useCallback

❌ The Mistake:

Recomputing expensive calculations on every render.

const result = expensiveFunction(data);
Enter fullscreen mode Exit fullscreen mode

✅ The Solution:

Use useMemo for expensive calculations and useCallback for functions.

const result = useMemo(() => expensiveFunction(data), [data]);

const memoizedFunction = useCallback(() => doSomething(), []);

Enter fullscreen mode Exit fullscreen mode
  1. Ignoring Component Re-Renders

❌ The Mistake:

Passing objects/functions directly as props, causing unnecessary re-renders.

<ChildComponent data={{ name: "John" }} /> // ❌ Bad practice
Enter fullscreen mode Exit fullscreen mode

✅ The Solution:

Use useMemo to avoid unnecessary re-renders.

const memoizedData = useMemo(() => ({ name: "John" }), []);
<ChildComponent data={memoizedData} />;
Enter fullscreen mode Exit fullscreen mode
  1. Not Cleaning Up Effects

❌ The Mistake:

Leaving event listeners or subscriptions open, causing memory leaks.

useEffect(() => {
  window.addEventListener("resize", handleResize);
});
Enter fullscreen mode Exit fullscreen mode

✅ The Solution:

Return a cleanup function inside useEffect.

useEffect(() => {
  const handleResize = () => console.log("Resized");
  window.addEventListener("resize", handleResize);

  return () => {
    window.removeEventListener("resize", handleResize);
  };
}, []);

Enter fullscreen mode Exit fullscreen mode

  1. Not Using Lazy Loading for Performance

❌ The Mistake:

Importing all components at once, increasing initial load time.

import HeavyComponent from "./HeavyComponent"; // ❌ Bad for performance
Enter fullscreen mode Exit fullscreen mode

✅ The Solution:

Use React.lazy and Suspense for code-splitting.

const HeavyComponent = React.lazy(() => import("./HeavyComponent"));

<Suspense fallback={<div>Loading...</div>}>
  <HeavyComponent />
</Suspense>;

Enter fullscreen mode Exit fullscreen mode
  1. Not Handling Errors Properly

❌ The Mistake:

Not wrapping components in an error boundary.

<MyComponent /> // ❌ Crashes the whole app if an error occurs
Enter fullscreen mode Exit fullscreen mode

✅ The Solution:

Use an Error Boundary to catch errors.

class ErrorBoundary extends React.Component {
  state = { hasError: false };

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    console.error("Error caught:", error, info);
  }

  render() {
    if (this.state.hasError) return <h2>Something went wrong.</h2>;
    return this.props.children;
  }
}

Enter fullscreen mode Exit fullscreen mode

Use it in your app:

<ErrorBoundary>
  <MyComponent />
</ErrorBoundary>

Enter fullscreen mode Exit fullscreen mode
  1. Not Using PropTypes or TypeScript

❌ The Mistake:

Not validating props, leading to unexpected bugs.

const Button = ({ text }) => <button>{text.toUpperCase()}</button>; // ❌ Can crash if text is undefined

Enter fullscreen mode Exit fullscreen mode

✅ The Solution:

Use PropTypes (for JavaScript) or TypeScript for type safety.

import PropTypes from "prop-types";

const Button = ({ text }) => <button>{text.toUpperCase()}</button>;

Button.propTypes = {
  text: PropTypes.string.isRequired,
};

Enter fullscreen mode Exit fullscreen mode

Or use TypeScript:

type ButtonProps = { text: string };

const Button: React.FC<ButtonProps> = ({ text }) => <button>{text.toUpperCase()}</button>;


Enter fullscreen mode Exit fullscreen mode

Final Thoughts

Avoiding these mistakes will make you a better React developer, improve your app’s performance, and reduce bugs. Mastering state management, performance optimization, and clean coding practices will help you build efficient and scalable React applications.

ReactJS #JavaScript #WebDevelopment #ReactMistakes #CodingTips #FrontendDevelopment

Top comments (0)