React Anti-Patterns 🚩

Patterns to avoid for writing efficient react code!

Β·

4 min read

1. Writing big a** components πŸ––

// navbar.jsx
import React, { useState } from "react";

const Main = () => {
  const [count, setCount] = useState(0);
  return (
    <main>
      <nav>
        <ul>
          <li>
            <div>Home</div>
          </li>
          <li>
            <div>About</div>
          </li>
          <li>
            <div>{count}</div>
          </li>
          <li>
            <div className="dropdown">
              <ul>
                <li>Option 1</li>
                <li>Option 2</li>
                <li>Option 3</li>
              </ul>
            </div>
          </li>
          <li>
            <div className="dropdown2">
              <ul>
                <li>Option 4</li>
                <li>Option 5</li>
                <li>Option 6</li>
              </ul>
            </div>
          </li>
          <li>
            <div className="dropdown3">
              <ul>
                <li>Option 7</li>
                <li>Option 8</li>
                <li>Option 9</li>
              </ul>
            </div>
          </li>
        </ul>
      </nav>
      <footer>
        <div className="footer-links">
          <li>Link 1</li>
          <li>Link 2</li>
          <li>Link 3</li>
        </div>
      </footer>
    </main>
  );
};

export default Code;

To make this more readable πŸ§‘β€πŸ« we can :-

  • Make a separate footer component. πŸ‘ŒπŸ»
  • Take out the 2 dropdowns in their own component. πŸ‘ŒπŸ»
// navbar.jsx
import React, { useState } from "react";
import Dropdown from "./dropdown.jsx";
import Footer from "./footer.jsx";

const Main = () => {
  const [count, setCount] = useState(0);
  return (
    <main>
      <nav>
        <ul>
          <li>
            <div>Home</div>
          </li>
          <li>
            <div>About</div>
          </li>
          <li>
            <div>{count}</div>
          </li>
        </ul>
        <Dropdown />
      </nav>
      <Footer />
    </main>
  );
};
// dropdown.jsx
import React, { useState } from "react";

const Dropdown = () => {
  return (
    <>
      <li>
        <div className="dropdown">
          <ul>
            <li>Option 1</li>
            <li>Option 2</li>
            <li>Option 3</li>
          </ul>
        </div>
      </li>
      <li>
        <div className="dropdown2">
          <ul>
            <li>Option 4</li>
            <li>Option 5</li>
            <li>Option 6</li>
          </ul>
        </div>
      </li>
      <li>
        <div className="dropdown3">
          <ul>
            <li>Option 7</li>
            <li>Option 8</li>
            <li>Option 9</li>
          </ul>
        </div>
      </li>
    </>
  );
};

export default Dropdown;
// footer.jsx
import React, { useState } from "react";

const Footer = () => {
  return (
    <footer>
      <div className="footer-links">
        <li>Link 1</li>
        <li>Link 2</li>
        <li>Link 3</li>
      </div>
    </footer>
  );
};

export default Footer;

2. Nesting components

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

  const handleClick = () => setCount(count + 1);

  const Child = () => {
    return <button onClick={handleClick}>+</button>;
  };

  return (
    <>
      <Child />
    </>
  );
}
  • Here, the child component uses a function defined inside the parent component.
  • This is a bad idea πŸ‘Ž, as every time the parent component is rendered πŸ‘€, the child is:-
    • Re-defined with a new memory address, which further leads to performance issue.

Better solution πŸ‘Œ

  • Don't ❌ create a child component at all.
  • Create a child component πŸ™†πŸ½ and pass the handleClick function as a prop to it.
const Child = ({ onClick }) => {
  return (
    <button onClick={onClick}>+</button>
  )
}

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

  const handleClick = () => setCount(count + 1);

  return (
    <Child onClick={handleClick} />
  );
}

3. Not memoizing repetitive tasks ✍️

import React, { useState } from "react";

export default function unMemoized() {
  const [count, setCount] = useState(0)
  const [countAgain, setCountAgain] = useState(0)

  const result = expensiveCalculation(count)

  return (
    <>
      <div className="result">{result}</div>
    </>
  )
}

πŸ‘Ž Every time any of the 2 state changes, the expensiveCalculation will re-run, which needless to say presents a performance-bottleneck ❌ (fancy term for slow performance)

useMemo hook comes and saves the day βœ…

πŸ‘‰ It saves the value of the function and re-calculates when the state (count, here) changes.

import React, { useState } from "react";

export default function Memoized() {
  const [count, setCount] = useState(0)
  const [countAgain, setCountAgain] = useState(0)

  const result = useMemo(() => expensiveCalculation(count), [count])

  return (
    <>
      <div className="result">{result}</div>
    </>
  )
}

4. Unnecessary divs

As we know JSX can only return oneπŸ₯‡parent element. Sometimes, we end up wrapping everything inside a good old div.

export default function DivsEverywhere {


  return (
    <div>
      <nav>I m really cool!!</nav>
      <main>Thanks for reading this!</main>
      <footer>Keep reading</footer>
    </div>
  );
}

These unnecessary divs present issues while making your UI accessible and styling it.

πŸ’ͺ A better way would be use a React Fragment (<>...</>) instead of a div.

export default function Frags() {


  return (
    <>
      <nav>I m really cool!!</nav>
      <main>Thanks for reading this!</main>
      <footer>Keep reading</footer>
    </>
  );
}

5. Prop Drilling πŸ™…πŸ½

Sometimes, you have a state in the parent component that you need access to in ⏬ child components. So, you pass it as a prop to the child.

export default function PropDrilling() {
  const [count] = useState(0);

  return <Child count={count} />;
}

function Child({ count }) {
  return <GrandChild count={count} />;
}

function GrandChild({ count }) {
  return <div>{count}</div>;
}
  • Only the GrandChild component needs the count state but it has to be passed through intermediate components like Child which is redundant.

2 solutions for this βœ”οΈ

  • Use a state management library like redux, zustand, easy-peasy
  • Use the context api provided by React

Let me show you how to use the Context API with the useContext hook

export default function Context() {
  const [count] = useState(0);

  return (
    <CountContext.Provider value={count}>
      <Child />
    </CountContext.Provider>
  );
}

function Child() {
  return <GrandChild />;
}

function GrandChild() {
  const count = useContext(CountContext);
  return <div>{count}</div>;
}
  • You define a provider in the parent component with the value that you want the child components to access.
  • Then you use the useContext hook in the child to access that value.

Thanks πŸ™ for reading this far. Stay tuned for more such content. πŸ”œ

Β