React Anti-Patterns π©
Patterns to avoid for writing efficient react code!
Photo by Paul Esch-Laurent on Unsplash
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. π