Table of contents
Recently, I was given a task to review a codebase in React and find ways to make the project more performant. Here are 10 common things I would typically look for when trying to improve performance and readability.
Not utilizing lazy import/code-splitting:
- Lazy loading or code splitting helps in reducing the initial bundle size and improving the application's load time by loading JavaScript modules only when they are needed. Failure to utilize lazy imports can result in unnecessarily large initial downloads.
// Without lazy import
import SomeComponent from './SomeComponent';
// With lazy import
const SomeComponent = React.lazy(() => import('./SomeComponent'));
Not cleaning up event listeners in
useEffect
:- Failing to clean up event listeners or subscriptions in the
useEffect
cleanup function can lead to memory leaks in the application.
- Failing to clean up event listeners or subscriptions in the
javascriptCopy codeuseEffect(() => {
const handleClick = () => {
// Handle click event
};
document.addEventListener('click', handleClick);
return () => {
// Always clear event listeners/timeouts in here
document.removeEventListener('click', handleClick);
};
}, []);
Big unoptimized images:
Large and unoptimized images can significantly impact page load times. Always optimize images for the web by compressing them and serving them in the appropriate size and format.
Use image optimization tools like
tinypng
.
Not using
useCallback
/useMemo
for unnecessary re-renders:- Failing to memoize functions or values using
useCallback
anduseMemo
can result in unnecessary re-renders of components.
- Failing to memoize functions or values using
javascriptCopy codeconst memoizedCallback = useCallback(() => {
// Function body
}, [/* Dependencies */]);
const memoizedValue = useMemo(() => {
// Value computation
}, [/* Dependencies */]);
Improper use of dependency arrays:
Incorrectly specifying dependencies in the dependency array of
useEffect
,useCallback
, oruseMemo
hooks can lead to unexpected behavior or bugs.Ensure all dependencies are included in the dependency array and avoid using the empty dependency array if your effect relies on any state or props.
Also remember to memoize the objects/arrays/functions itself that are in the dependency array as it will create new references which will cause re-renders
Not caching data:
- Failing to cache data can result in unnecessary network requests and decreased application performance. Utilize caching mechanisms like
localStorage
,sessionStorage
, or caching libraries such asreact-query
.
- Failing to cache data can result in unnecessary network requests and decreased application performance. Utilize caching mechanisms like
No infinite scroll/pagination/virtualization:
Loading all data at once without implementing infinite scroll, pagination, or virtualization can result in poor performance, especially with large datasets. Implementing these techniques can improve user experience and reduce load times.
Example: Implement infinite scroll using libraries like
react-infinite-scroll-component
orreact-virtualized
or pagination using server-side pagination techniques.
Inefficient API calls:
Inefficient API calls, such as making redundant or unnecessary requests, can negatively impact performance and increase server load. Optimize API calls by batching requests, implementing caching, or using optimized query parameters.
React-query for more efficient data fetching or debounce/throttle requests to prevent unnecessary server load.
Inefficient component design:
Poorly designed components with excessive re-renders or unnecessary state can lead to performance issues. Optimize component design by breaking down complex components into smaller ones, using memoization, and avoiding unnecessary state.
Example: Refactor complex components into smaller, reusable ones and utilize React's context API for state management and react-query for async state management.
Adding unnecessary libraries:
Including unnecessary libraries in the project can bloat the bundle size and increase load times. Evaluate whether a library is truly necessary for your project and consider alternatives or custom solutions.
Eg, installing whole lodash or installing more than one library that achieves the same functionality
Stick with one UI library that will cover all of your needs
Conclusion
By following these best practices and optimizing your React codebase, you can create high-performance, maintainable, and user-friendly applications that provide a seamless experience for your users. I will go in details over some of the techniques in future posts. Remember that optimization is an ongoing process, and continuously monitoring and refining your codebase is essential for ensuring optimal performance as your project evolves.
Thank you for reading, let me know your thoughts! And share more tips in the comments!