10 React Best Practises I’ve Learned From Code Reviews

Sedang Trending 2 bulan yang lalu

Want to study React faster? Here are immoderate lessons I’ve learned complete nan years.

Poorna Theekshana

Bits and Pieces

Being a React developer isn’t an easy point to do. Learning nan model is 1 thing. But, taking your skills to nan adjacent level is another.

You request to beryllium capable to constitute cleanable React codification while ensuring that it’s optimal astatine nan aforesaid time. And, nan champion measurement that I’ve learned that is done my codification reviewed pinch seniors.

So, I’d for illustration to stock nan apical 10 champion practises that I’ve learned during my codification reviews to thief you get up faster!

TL;DR: This article outlines 10 champion practices for React improvement gleaned from codification reviews:

1. Component Modularity: Use independent Bit Components for modularity, enhancing reusability, testing, and maintainability.

2. Follow The Single Responsibility Principle: Ensure each constituent has a azygous intent for cleaner, much maintainable code.

3. Avoid Unnecessary Re-renders: Optimize capacity by preventing unnecessary re-renders pinch techniques for illustration useCallback and React.memo.

4. Use Prop Types and TypeScript: Employ PropTypes aliases TypeScript to forestall type-related errors and heighten codification reliability.

5. Use Functional Components alternatively of Class: Start caller projects pinch Functional Components for simplicity, but support consistency pinch existing standards.

6. Avoid Prop Drilling: Use React’s Context API to debar passing props down aggregate layers of components unnecessarily.

7. Properly Handle Errors (Error Boundaries): Implement correction boundaries to forestall cascading failures and guarantee a smoother personification experience.

8. Code Splitting: Enhance capacity by loading only basal parts of codification erstwhile required utilizing move imports aliases React.lazy.

9. Accessibility: Make applications inclusive by utilizing semantic HTML, providing replacement matter for images, and ensuring keyboard navigation.

10. Documentation: Document your codification comprehensively to facilitate knowing and collaboration among developers.

Firsty, it’s important to make judge your React components are module and composable. Essentially, you request to make judge that your React components are reusable successful quality and tin beryllium moved astir without immoderate breaking changes.

To do so, our squad moved from NPX to Bit to create React components arsenic independent Bit Components. With NPX, you’re trapped successful a monolith, but pinch Bit, you’re capable to design, develop, build and type your components successful an independent manner.

And we’ve besides been capable to summation our rhythm clip pinch its CI Server — Ripple Server that fundamentally propagates constituent changes crossed nan tree.

By adopting specified modularity into your code, you tin execute nan following:

  • Enhances codification reusability: Pieces of codification go for illustration Lego bricks, usable successful various configurations, redeeming clip and effort.
  • Simplifies testing processes: It makes it easier to trial individual components by identifying imaginable problems and ensuring much reliable code.
  • Improves wide UI maintainability: With modular components, making changes aliases fixing bugs successful 1 portion doesn’t disrupt nan full application, starring to easier maintenance.

For example, this codification demonstrates really to usage React components to create a modular structure, separating UI elements from logic.

It consists of a Presentational Component (MyComponent) responsible for rendering UI elements and a Container Component (MyContainer) managing logic and state.

// Presentational Component
const MyComponent = ({ connection }) => (
<div>
<h1>{message}</h1>
</div>
);

// Container Component
const MyContainer = () => {
const [message, setMessage] = useState('Hello from MyContainer!');

useEffect(() => {
setTimeout(() => {
setMessage('Data loaded successfully!');
}, 2000);
}, []);

return <MyComponent message={message} />;
};

This modular attack streamlines improvement and enhances nan codebase’s manageability.

Bit enables building independent, modular, and composable components, making them reusable and simple.

If you’re willing successful moving pinch Bit, cheque retired this end-to-end guide:

I utilized to creation components wherever I chunked everything onto a azygous component. For example, backmost successful nan day, erstwhile I created components, it often looked for illustration this:

import React, { useState, useEffect } from 'react';
import axios from 'axios';

const AxiosComponent = () => {
const [data, setData] = useState(null);
const [error, setError] = useState(null);

useEffect(() => {
const fetchData = async () => {
effort {
const consequence = await axios.get('https://api.example.com/data');
setData(response.data);
} drawback (error) {
setError(error);
}
};

fetchData();

// Cleanup function
return () => {
// Optionally grip immoderate cleanup needed
};
}, []); // Empty dependency array to tally effect only once

return (
<div>
{data ? (
<div>
<h2>Data Received:</h2>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
) : (
<p>Loading...</p>
)}
{error && <p>Error: {error.message}</p>}
</div>
);
};

export default AxiosComponent;

For instance, if I was invoking an API, I’d see that codification wrong nan React constituent arsenic well. But, successful reality, that’s a bad practise. Instead, it’s amended to travel nan Single Responsibility Principle.

By doing so, you guarantee that each constituent has a azygous purpose, aligning pinch nan Single Responsibility Principle (SRP). This practice:

  • Promotes cleaner and much maintainable code: By assigning 1 clear intent to each component, nan codebase becomes much readable and easier to maintain.
  • Facilitates easier testing and debugging processes: Components pinch a azygous work are much straightforward to test, and debugging becomes little complex.

So, if we were to rewrite this aforesaid bad codification pinch nan Single Responsibility Principle, you’d person a specialized React Hook, useDataFetcher, to tidy up nan mess.

This hook focuses solely connected fetching data, adhering to nan Single Responsibility Principle.

// DataFetcher Hook
const useDataFetcher = () => {
// ... codification for information fetching utilizing Axios aliases immoderate different library
const fetchData = async () => {
// ... fetch information logic
};

return { fetchData };
};

// Presentation Component
const Presentation = ({ information }) => {
// ... codification for presenting nan data
};

// Component utilizing DataFetcher Hook
const App = () => {
const { fetchData } = useDataFetcher();

useEffect(() => {
fetchData();
}, []);

return (
<div>
<Presentation />
</div>
);
};

This implies nan codebase and improves really clear and testable our components are. Plus, your components go much maintainable.

Each constituent now has a circumstantial job, pursuing nan thought that 1 constituent should do 1 point well. For instance, successful this case, we’ve neatly organized nan data-fetching process into a reusable hook, making our components much focused and maintainable.

Optimizing for capacity successful nan fast-paced world of React involves steering clear of unnecessary re-renders. This practice:

  • Enhances wide exertion efficiency: By preventing unnecessary re-renders, nan exertion runs much efficiently, providing a amended personification experience.
  • Mitigates capacity bottlenecks: Memoization techniques, specified arsenic utilizing React.memo aliases nan useMemo hook, thief mitigate capacity bottlenecks by ensuring components update only erstwhile necessary.

Example:

In this example, we’ll research really to efficiently negociate authorities updates and forestall unnecessary re-renders utilizing nan useCallback hook, ensuring optimal capacity successful your application.

ParentComponent.js

import React, { useState, useCallback } from 'react';
import ChildComponent from './ChildComponent';

const ParentComponent = () => {
const [counter, setCounter] = useState(0);

// Using useCallback to memoize nan onClick handler
const onClick = useCallback(() => {
console.log('Handler executed');
// Perform immoderate logic here
}, []);

return (
<div>
<button onClick={() => setCounter(counter + 1)}>Increase Counter</button>
<h2>{counter}</h2>
{/* Passing memoized onClick handler to ChildComponent */}
<ChildComponent name="child" onClick={onClick} />
</div>
);
};
export default ParentComponent;

ChildComponent.js

import React from 'react';

const ChildComponent = ({ name, onClick }) => {
console.log(${name} constituent rendered );

return (
<div>
<h2>{name}</h2>
{/* Triggering nan memoized onClick handler */}
<button onClick={onClick}>Click me</button>
</div>
);
};

export default React.memo(ChildComponent);

In this example, nan ParentComponent renders a antagonistic and a ChildComponent. The onClick handler is memoized utilizing useCallback to forestall unnecessary re-renders of nan ChildComponent. The memoized handler is past passed down to nan ChildComponent arsenic a prop. The console logs thief exemplify erstwhile each constituent is rendered.

Tip, don’t complete memomize your app. If you complete do it, you spell to nan bad broadside of it and tin acquisition terrible capacity issues. So, a norm of thumb is to memoize only compute dense operations.

Preventing type-related errors is important successful development. We started our task pinch JavaScript, and that was absolute troublesome! Weeks aft penning our code, we couldn’t remember:

  1. The API payloads.
  2. The prop definitions

So, essentially, we couldn’t support our app. So, we refactored nan full task to TypeScript. By doing so, this fto us:

  • Prevent type-related pitfalls: By introducing PropTypes aliases adopting TypeScript, you create a information nett that catches imaginable type-related issues during development.
  • Have a information nett for codification reliability: This proactive attack enhances codification reliability and ensures your exertion behaves arsenic expected.

Example:

Imagine a constituent responsible for displaying personification details, and it receives a prop called userInfo:

// InsecureComponent - Component without Type Annotations
const InsecureComponent = ({ userInfo }) => (
<div>
<p>Name: {userInfo.name}</p>
<p>Age: {userInfo.age}</p>
</div>
);

Without prop types, it mightiness beryllium unclear what building userInfo should follow. Now, let's present Prop Types to bring clarity and debar imaginable pitfalls:

// SecureComponent - Component pinch Prop Types
import PropTypes from 'prop-types';

const SecureComponent = ({ userInfo }) => (
<div>
<p>Name: {userInfo.name}</p>
<p>Age: {userInfo.age}</p>
</div>
);

SecureComponent.propTypes = {
userInfo: PropTypes.shape({
name: PropTypes.string.isRequired,
age: PropTypes.number.isRequired,
}).isRequired,
};

Adding Prop Types not only documents nan expected building of userInfo but besides serves arsenic a adjuvant reminder erstwhile revisiting nan code.

This elemental believe importantly contributes to codification reliability, preventing imaginable issues and making nan improvement acquisition smoother.

Transitioning from people components to functional components pinch hooks has been transformative.

The Functional components introduced nan Hooks API that made it simpler and cleaner to create and negociate React components.

So, a bully norm of thumb is, if you’re starting a caller task successful 2024, commencement pinch Functional Components. However, location tin beryllium cases wherever you’d still usage a Class Component — For example, if you’re building an Error Boundary, you’d still request to usage a Class Component.

But, let’s opportunity you’re moving connected a task that started disconnected pinch Class Components. What should you do now?

Well, nan reply is simple. Stick to your task standards. Continue utilizing Class Components, but don’t person a operation of nan 2 arsenic it tin get confusing to navigate done your codebase.

6. Avoid Prop Drilling

Prop Drilling is thing I struggled pinch erstwhile I started disconnected pinch React. I utilized to walk props down layers of components wherever immoderate layers didn’t moreover request to usage nan prop.

For instance, here’s a bully illustration of prop drilling:

// Component astatine nan Bottom of nan Tree
const BottomComponent = ({ information }) => (
<div>{data}</div>
);

// Intermediate Components Prop-Drilling
const IntermediateComponent = ({ information }) => (
<BottomComponent data={data} />
);

// Top-Level Component Initiating Prop Drilling
const TopComponent = ({ information }) => (
<IntermediateComponent data={data} />
);

You person nan TopComponent passing information down each nan measurement to your BottomComponent done nan IntermediateComponent moreover though it isn't being utilized there.

That’s unnecessary accusation to nan information. So, really tin we do better? Well, leverage React’s Context API to do so:

// Context Setup
const DataContext = React.createContext();

const ContextProvider = ({ children }) => {
const information = //... get information from somewhere;
return (
<DataContext.Provider value={data}>
{children}
</DataContext.Provider>
);
};

// Context Consumer Component
const ContextConsumerComponent = () => (
<DataContext.Consumer>
{data => <div>{data}</div>}
</DataContext.Consumer>
);

The Context API is simply a measurement of passing props down constituent trees without utilizing Props. Instead, you create a Context Provider and a Consumer and immoderate constituent that is wrapped wrong your Provider tin usage information wrong your context.

We conscionable solved prop drilling!

Errors are an unavoidable portion of package development, but really you negociate them defines your application’s resilience.

Implementing correction boundaries acts arsenic a information net, preventing nan full exertion from crashing erstwhile unexpected errors occur.

Example:

Consider a script wherever an correction occurs during nan mounting of a component, perchance causing a cascade of failures:

ErrorBoundary.tsx

import React, { Component, ErrorInfo, ReactNode } from 'react';

interface ErrorBoundaryProps {
children: ReactNode;
}

interface ErrorBoundaryState {
hasError: boolean;
}

class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
state: ErrorBoundaryState = { hasError: mendacious };

fixed getDerivedStateFromError(_: any) {
return { hasError: existent };
}

componentDidCatch(error: Error, errorInfo: ErrorInfo) {
console.error('Error caught by correction boundary:', error, errorInfo);
// You tin log nan correction aliases study it to a work for further analysis
}

render() {
if (this.state.hasError) {
return <div>Something went wrong!</div>;
}

return this.props.children;
}
}

App.tsx

import React from 'react';
import ErrorBoundary from './ErrorBoundary';

class BuggyComponent extends React.Component {
componentDidMount() {
// Simulate an correction during constituent mounting
propulsion caller Error('Error during mounting');
}

render() {
return <div>This is simply a buggy component!</div>;
}
}

function App() {
return (
<div>
<h1>Error Handling Demo</h1>
<ErrorBoundary>
<BuggyComponent />
</ErrorBoundary>
</div>
);
}

export default App;

Without correction boundaries, specified unchecked errors could lead to a cascade of failures. With correction boundaries successful place, nan exertion gracefully handles errors, ensuring a smoother personification acquisition moreover successful nan look of unexpected glitches.

Enhancing nan capacity of your React exertion goes beyond businesslike components. Code splitting, a potent technique, enables loading only nan basal parts of your codification erstwhile required, reducing first loading times and improving wide responsiveness.

Example:

Imagine a ample exertion loading each its components upfront, resulting successful sluggish performance:

// Loading All Components astatine Once
import ComponentA from './ComponentA';
import ComponentB from './ComponentB';
import ComponentC from './ComponentC';

// Implementing Code Splitting pinch React.lazy
const LazyLoadedComponent = React.lazy(() => import('./LazyLoadedComponent'));

// Loading Components On Demand
const App = () => (
<div>
<ComponentA />
<ComponentB />
<ComponentC />
<Suspense fallback={<div>Loading...</div>}>
<LazyLoadedComponent />
</Suspense>
</div>
);

By utilizing codification splitting done move imports aliases React.lazy, your exertion becomes a nimble, on-demand loader of codification chunks. This translator reduces first loading times and enhances nan wide responsiveness of your React application.

Crafting applications that are inclusive and accessible to each users, including those pinch disabilities, is simply a commendable goal. By embracing practices specified arsenic utilizing semantic HTML, providing replacement matter for images, and ensuring keyboard navigation, you create a web acquisition that leaves nary 1 behind.

  • React exertion becomes accessible to users pinch divers needs, fostering a much inclusive integer environment.
  • This ensures your exertion complies pinch standards, making it much apt to meet ineligible requirements and manufacture regulations.

Example:

// Interface without Accessibility Features
const InaccessibleInterface = () => (
<div>
<div>Content without semantic HTML</div>
<img src="image.jpg" alt="A ornamental image" />
<div>Non-accessible content</div>
</div>
);

// Interface pinch Accessibility Features
const AccessibleInterface = () => (
<div>
<header>
<h1>Accessible Web Page</h1>
</header>
<img src="image.jpg" alt="A meaningful explanation of nan image" />
<main>
<p>Accessible contented pinch semantic HTML</p>
</main>
</div>
);

By implementing changes specified arsenic utilizing semantic HTML and providing replacement matter for images, your React exertion transforms into a welcoming and inclusive integer space, ensuring a affirmative acquisition for users of each abilities.

Code is not conscionable for machines; it’s a intends of connection among developers. Documenting your codification is for illustration providing a roadmap for others to navigate and understand your creation.

  • Comprehensive archiving offers clear insights, helping developers understand nan intricacies of your codebase.
  • Documentation fosters a collaborative improvement environment, enabling squad members to activity much efficiently.

Imagine that developers are required to navigate a maze without a representation if location is nary archiving for a codebase. Now ideate nan aforesaid codebase pinch extended archiving that provides clear explanations for anyone exploring its subtleties. With nan thief of this thorough documentation, developers tin confidently and easy understand nan complexities of nan software.

Well, that was a batch to digest. But, that’s fundamentally worldly that I’ve learned done my years of moving pinch React. And, I dream that it will beryllium of bully usage to you.

If you person immoderate further practises that you’d for illustration to share, consciousness free to driblet them successful nan discussions!

Thank you for reading!