20 Essential React Tricks Every Developer Must Know
Jagroop Singh

Jagroop Singh @jagroop2001

About: 👨‍💻 Full Stack Developer | 🤖 Machine Learning Developer | 🤝 Dev Relations Pro – 💼 Available for Hire | 24k+ Followers | 355k+ Views

Location:
India
Joined:
Apr 5, 2022

20 Essential React Tricks Every Developer Must Know

Publish Date: Oct 31 '24
41 14

React is incredibly powerful, but mastering it means going beyond the basics and learning some lesser-known tricks to streamline development. Here’s a rundown of my personal favourite 20 React tricks that can boost your productivity and help you write cleaner, more effective code. Let’s dive straight into examples!


1. Short-Circuit Evaluation for Conditional Rendering

Avoid verbose if statements for conditional rendering with short-circuit evaluation.

{isLoading && <Spinner />}
Enter fullscreen mode Exit fullscreen mode

This renders the <Spinner /> only when isLoading is true, keeping your JSX clean.


2. Dynamic Class Names with classnames Library

The classnames library makes it easy to conditionally apply classes.

npm install classnames
Enter fullscreen mode Exit fullscreen mode
import classNames from 'classnames';

const buttonClass = classNames({
  'btn': true,
  'btn-primary': isPrimary,
  'btn-secondary': !isPrimary,
});

<button className={buttonClass}>Click Me</button>
Enter fullscreen mode Exit fullscreen mode

3. Memoizing Expensive Calculations with useMemo

If a computation is costly, memoize it so React doesn’t recompute unnecessarily.

const sortedData = useMemo(() => data.sort(), [data]);
Enter fullscreen mode Exit fullscreen mode

This recalculates sortedData only when data changes.


4. Debouncing Inputs with useEffect

Avoid constant re-renders by debouncing input changes.

const [value, setValue] = useState('');
const [debouncedValue, setDebouncedValue] = useState('');

useEffect(() => {
  const handler = setTimeout(() => setDebouncedValue(value), 500);
  return () => clearTimeout(handler);
}, [value]);

<input value={value} onChange={(e) => setValue(e.target.value)} />
Enter fullscreen mode Exit fullscreen mode

5. Custom Hooks for Reusable Logic

Encapsulate logic in a custom hook to reuse it across components.

function useFetch(url) {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetch(url).then(res => res.json()).then(setData);
  }, [url]);

  return data;
}

const Component = () => {
  const data = useFetch('/api/data');
  return <div>{data ? JSON.stringify(data) : 'Loading...'}</div>;
};
Enter fullscreen mode Exit fullscreen mode

6. Lazy Loading Components with React.lazy

Optimize loading time by splitting your components.

const LazyComponent = React.lazy(() => import('./LazyComponent'));

function App() {
  return (
    <React.Suspense fallback={<div>Loading...</div>}>
      <LazyComponent />
    </React.Suspense>
  );
}
Enter fullscreen mode Exit fullscreen mode

7. Accessing Previous Props or State with useRef

To access previous state values, use useRef.

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

useEffect(() => {
  prevCount.current = count;
}, [count]);

console.log(`Previous: ${prevCount.current}, Current: ${count}`);
Enter fullscreen mode Exit fullscreen mode

8. Avoid Re-renders by Passing Functions to useCallback

If a function doesn’t need to change, memoize it with useCallback.

const increment = useCallback(() => setCount(count + 1), [count]);
Enter fullscreen mode Exit fullscreen mode

9. Destructuring Props for Cleaner Code

Destructure props right in the function parameters.

const User = ({ name, age }) => (
  <div>{name} is {age} years old</div>
);
Enter fullscreen mode Exit fullscreen mode

10. React.Fragment for Grouping Elements Without Extra Divs

Wrap elements without adding an extra DOM node.

<>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</>
Enter fullscreen mode Exit fullscreen mode

11. Error Boundaries for Catching JavaScript Errors

Catch errors in child components to prevent the whole app from crashing.

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

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

  render() {
    if (this.state.hasError) return <h1>Something went wrong.</h1>;
    return this.props.children;
  }
}
Enter fullscreen mode Exit fullscreen mode

Jagroop2001 (Jagroop) · GitHub

👨‍💻 Full Stack Developer | 🤖 Machine Learning Developer | 🤝 Dev Relations Pro – 💼 Available for Hire - Jagroop2001

favicon github.com

12. Using PropTypes for Prop Validation

Catch bugs early by defining prop types.

import PropTypes from 'prop-types';

function MyComponent({ name }) {
  return <div>{name}</div>;
}

MyComponent.propTypes = {
  name: PropTypes.string.isRequired,
};
Enter fullscreen mode Exit fullscreen mode

13. State Reducers with useReducer

For complex state logic, useReducer can be more efficient.

const initialState = { count: 0 };

function reducer(state, action) {
  switch (action.type) {
    case 'increment': return { count: state.count + 1 };
    case 'decrement': return { count: state.count - 1 };
    default: return state;
  }
}

const [state, dispatch] = useReducer(reducer, initialState);
Enter fullscreen mode Exit fullscreen mode

14. useLayoutEffect for DOM Manipulations

Run effects after DOM updates but before paint.

useLayoutEffect(() => {
  console.log("Layout effect");
}, []);
Enter fullscreen mode Exit fullscreen mode

15. Encapsulate State Logic with Context and useContext

Create global state without prop drilling.

const ThemeContext = React.createContext();

function MyComponent() {
  const theme = useContext(ThemeContext);
  return <div style={{ background: theme }}>Hello!</div>;
}
Enter fullscreen mode Exit fullscreen mode

16. Avoid Inline Function Definitions in JSX

Defining functions inline causes re-renders. Instead, define them outside.

const handleClick = () => console.log("Clicked");

<button onClick={handleClick}>Click Me</button>
Enter fullscreen mode Exit fullscreen mode

17. Use Optional Chaining in JSX for Safe Property Access

Handle null or undefined values gracefully.

<p>{user?.name}</p>
Enter fullscreen mode Exit fullscreen mode

18. Use the key Prop to Avoid Re-rendering Issues

Always use unique keys when rendering lists.

{items.map(item => (
  <div key={item.id}>{item.name}</div>
))}
Enter fullscreen mode Exit fullscreen mode

19. Export Components with Named Exports for Better Import Control

Named exports make importing specific components easier.

export const ComponentA = () => <div>A</div>;
export const ComponentB = () => <div>B</div>;
Enter fullscreen mode Exit fullscreen mode

Then import as needed:

import { ComponentA } from './Components';
Enter fullscreen mode Exit fullscreen mode

20. Reusable Component Patterns: Higher-Order Components (HOCs)

Wrap components with HOCs to add extra logic.

function withLogging(WrappedComponent) {
  return function Wrapped(props) {
    console.log('Component Rendered');
    return <WrappedComponent {...props} />;
  };
}

const MyComponentWithLogging = withLogging(MyComponent);
Enter fullscreen mode Exit fullscreen mode

Mastering these tricks will help you write more concise, readable, and efficient React code! Happy coding!

Comments 14 total

  • Stefan Neidig
    Stefan NeidigOct 31, 2024

    In 12 what is the benefit of prop types over using Interfaces. Haven't seen this before so I was wondering.

    • Joel Sullivan
      Joel SullivanOct 31, 2024

      Personally I prefer TypeScript interfaces over the older PropTypes.

      • Jagroop Singh
        Jagroop SinghNov 1, 2024

        Yes me too, but for javascript based React project it's very handy. @joels

    • Jagroop Singh
      Jagroop SinghNov 1, 2024

      @dasheck0 ,
      In React (if I talk about JS based), PropTypes allow runtime type checking for props, catching errors during execution, whereas TypeScript interfaces provide static type checking at compile time, which can prevent errors earlier.

  • john
    johnNov 1, 2024

    Destructuring props directly in the function parameters is my favorite approach—it enhances code readability significantly. While some people argue that it's too common to be noteworthy, I disagree. Previously, I worked on a React project with code that was messy: excessive prop drilling and constant references like props.name and props.user.address.pincode. Dealing with this was frustrating, which is why destructuring has become my go-to.

  • caga
    cagaNov 1, 2024

    Yes this one :
    Export Components with Named Exports for Better Import Control
    My senior also pointed out me to use like this as explained in 19 tip instead of export default.
    What's the reason behind using this and why not I prefer export deafault componentA.

    • Jagroop Singh
      Jagroop SinghNov 1, 2024

      @paxnw ,
      Using named exports instead of default exports provides better control and clarity when importing components.
      With named exports, you can import multiple components from a single module, which helps avoid naming collisions and makes it clear what is being imported.
      This practice also enhances code readability and maintainability by explicitly defining what components are available for use, making it easier to track dependencies in larger codebases.

  • Robin Kretzschmar
    Robin KretzschmarNov 4, 2024

    I prefer classcat over classnames package for cases where I don't want to use interpolated strings. I saw some performance comparisons some time ago and stuck with it ever since.

  • Anjan Talatam
    Anjan TalatamNov 5, 2024

    Prefer clsx over classnames. classnames is ~3 times bigger than clsx.
    npm trends

    Image description

  • Bare Metal Email
    Bare Metal EmailNov 5, 2024

    Nice

Add comment