100+ React Tips & Tricks For Beginners To Experts ✨

Sh Raj - Aug 10 - - Dev Community

100+ React Tips & Tricks For Beginners To Experts ✨

React, a popular JavaScript library for building user interfaces, is widely used due to its efficiency, flexibility, and powerful features. Whether you’re a beginner or an expert, there’s always something new to learn. In this guide, we’ll explore 101 tips and tricks to help you master React, covering everything from the basics to advanced techniques.

Table of Contents

  1. Understanding React Basics
    • 1.1. JSX: The Basics
    • 1.2. Component Lifecycle
    • 1.3. Functional vs. Class Components
    • 1.4. Props and State
  2. Working with Components
    • 2.1. Reusable Components
    • 2.2. PropTypes for Type Checking
    • 2.3. Controlled vs. Uncontrolled Components
    • 2.4. Conditional Rendering
  3. State Management
    • 3.1. Using useState and useReducer
    • 3.2. Global State with Context API
    • 3.3. Redux for Complex State Management
    • 3.4. Zustand: A Lightweight Alternative to Redux
  4. Handling Side Effects
    • 4.1. Using useEffect Hook
    • 4.2. Cleanup Functions in useEffect
    • 4.3. Fetching Data with useEffect
    • 4.4. Optimizing Performance with Memoization
  5. Advanced Component Patterns
    • 5.1. Higher-Order Components (HOCs)
    • 5.2. Render Props
    • 5.3. Compound Components
    • 5.4. Custom Hooks
  6. Optimizing Performance
    • 6.1. Lazy Loading Components
    • 6.2. Code Splitting with React.lazy and Suspense
    • 6.3. Memoizing with React.memo
    • 6.4. Using React.PureComponent for Performance Gains
  7. Routing in React
    • 7.1. Basic Routing with React Router
    • 7.2. Nested Routes
    • 7.3. Dynamic Routing
    • 7.4. Programmatic Navigation
  8. Form Handling
    • 8.1. Handling Form Inputs
    • 8.2. Validation with Formik and Yup
    • 8.3. Using Custom Hooks for Form Management
    • 8.4. File Uploads in React
  9. Testing React Applications
    • 9.1. Unit Testing with Jest
    • 9.2. Component Testing with React Testing Library
    • 9.3. Mocking API Calls in Tests
    • 9.4. End-to-End Testing with Cypress
  10. Building and Deploying React Apps
    • 10.1. Setting Up with Create React App
    • 10.2. Custom Webpack Configurations
    • 10.3. Optimizing for Production
    • 10.4. Deploying to Vercel, Netlify, and Other Platforms
  11. Styling React Components
    • 11.1. CSS Modules in React
    • 11.2. Styled Components for Modern UI
    • 11.3. Tailwind CSS with React
    • 11.4. Theming with Styled Components
  12. React with TypeScript
    • 12.1. Setting Up TypeScript in React
    • 12.2. TypeScript Generics in React
    • 12.3. Advanced Types in React
    • 12.4. Migrating a JavaScript Project to TypeScript
  13. Accessibility in React
    • 13.1. Keyboard Navigation and Focus Management
    • 13.2. Using ARIA Attributes in React
    • 13.3. Accessible Forms and Buttons
    • 13.4. Testing Accessibility with Lighthouse
  14. React and SEO
    • 14.1. Server-Side Rendering (SSR) with Next.js
    • 14.2. Static Site Generation (SSG) with Next.js
    • 14.3. Managing Metadata with React Helmet
    • 14.4. Optimizing Images for SEO
  15. React Best Practices
    • 15.1. Structuring Your React Project
    • 15.2. Using ESLint and Prettier
    • 15.3. Avoiding Common Pitfalls
    • 15.4. Writing Clean, Maintainable Code

1. Understanding React Basics

1.1. JSX: The Basics

JSX (JavaScript XML) allows you to write HTML within JavaScript. It makes your code more readable and expressive. Here's an example:

function HelloWorld() {
  return <h1>Hello, World!</h1>;
}
Enter fullscreen mode Exit fullscreen mode

1.2. Component Lifecycle

Understanding the lifecycle of a React component is crucial. In class components, lifecycle methods like componentDidMount, componentDidUpdate, and componentWillUnmount are used to manage side effects.

1.3. Functional vs. Class Components

React introduced Hooks in version 16.8, making functional components more powerful. While class components are still used, functional components with hooks are now the preferred way to build React components.

// Class Component
class MyComponent extends React.Component {
  render() {
    return <div>Class Component</div>;
  }
}

// Functional Component
function MyComponent() {
  return <div>Functional Component</div>;
}
Enter fullscreen mode Exit fullscreen mode

1.4. Props and State

Props are used to pass data from parent to child components, while state is used to manage data within a component. Here’s a simple example:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

function App() {
  return <Welcome name="Alice" />;
}
Enter fullscreen mode Exit fullscreen mode

2. Working with Components

2.1. Reusable Components

Creating reusable components is key to maintaining a clean and scalable codebase. For example, a button component that can be used throughout your app:

function Button({ label, onClick }) {
  return <button onClick={onClick}>{label}</button>;
}

function App() {
  return <Button label="Click Me" onClick={() => alert('Button Clicked!')} />;
}
Enter fullscreen mode Exit fullscreen mode

2.2. PropTypes for Type Checking

PropTypes allow you to enforce type checking in your components, helping to catch errors early:

import PropTypes from 'prop-types';

function Greeting({ name }) {
  return <h1>Hello, {name}</h1>;
}

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

2.3. Controlled vs. Uncontrolled Components

Controlled components are those where form data is handled by the state in React, while uncontrolled components maintain their own state.

// Controlled Component
function ControlledInput() {
  const [value, setValue] = useState('');

  return (
    <input
      value={value}
      onChange={(e) => setValue(e.target.value)}
    />
  );
}

// Uncontrolled Component
function UncontrolledInput() {
  const inputRef = useRef();

  return <input ref={inputRef} />;
}
Enter fullscreen mode Exit fullscreen mode

2.4. Conditional Rendering

Conditionally render components based on certain criteria:

function App({ isLoggedIn }) {
  return (
    <div>
      {isLoggedIn ? <h1>Welcome back!</h1> : <h1>Please sign in.</h1>}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

3. State Management

3.1. Using useState and useReducer

useState is the simplest way to manage state in functional components. For more complex state logic, useReducer is recommended.

// useState Example
function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>{count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

// useReducer Example
function counterReducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(counterReducer, { count: 0 });

  return (
    <div>
      <p>{state.count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

3.2. Global State with Context API

Context API is useful for passing data through the component tree without having to pass props manually at every level.

const ThemeContext = createContext();

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar() {
  return

 (
    <div>
      <ThemedButton />
    </div>
  );
}

function ThemedButton() {
  const theme = useContext(ThemeContext);
  return <button className={theme}>Themed Button</button>;
}
Enter fullscreen mode Exit fullscreen mode

3.3. Redux for Complex State Management

Redux is a powerful library for managing complex state in large applications.

import { createStore } from 'redux';

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

const store = createStore(counterReducer);

store.dispatch({ type: 'increment' });
console.log(store.getState()); // { count: 1 }
Enter fullscreen mode Exit fullscreen mode

3.4. Zustand: A Lightweight Alternative to Redux

Zustand is a small, fast state-management library for React.

import create from 'zustand';

const useStore = create((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
}));

function Counter() {
  const { count, increment } = useStore();
  return (
    <div>
      <p>{count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

4. Handling Side Effects

4.1. Using useEffect Hook

useEffect is used for managing side effects such as data fetching, subscriptions, and manual DOM changes.

function App() {
  useEffect(() => {
    document.title = "React App";
  }, []);

  return <div>Check the document title!</div>;
}
Enter fullscreen mode Exit fullscreen mode

4.2. Cleanup Functions in useEffect

Always use cleanup functions to avoid memory leaks, especially when dealing with subscriptions or timers.

function Timer() {
  useEffect(() => {
    const timer = setInterval(() => console.log("Tick"), 1000);

    return () => clearInterval(timer);
  }, []);

  return <div>Check the console for ticks!</div>;
}
Enter fullscreen mode Exit fullscreen mode

4.3. Fetching Data with useEffect

You can fetch data within useEffect, and manage the state accordingly.

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

  useEffect(() => {
    fetch('https://api.example.com/data')
      .then(response => response.json())
      .then(data => setData(data));
  }, []);

  return (
    <div>
      {data ? <pre>{JSON.stringify(data, null, 2)}</pre> : "Loading..."}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

4.4. Optimizing Performance with Memoization

Use memoization to optimize the performance of your React app by preventing unnecessary re-renders.

const MemoizedComponent = React.memo(function MyComponent({ value }) {
  console.log('Rendered');
  return <div>{value}</div>;
});
Enter fullscreen mode Exit fullscreen mode

5. Advanced Component Patterns

5.1. Higher-Order Components (HOCs)

HOCs are functions that take a component and return a new component with added functionality.

function withLogging(WrappedComponent) {
  return function(props) {
    console.log("Rendering", WrappedComponent.name);
    return <WrappedComponent {...props} />;
  };
}

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

5.2. Render Props

Render props allow you to share code between components using a prop whose value is a function.

function MouseTracker({ render }) {
  const [position, setPosition] = useState({ x: 0, y: 0 });

  const handleMouseMove = (event) => {
    setPosition({
      x: event.clientX,
      y: event.clientY
    });
  };

  return (
    <div style={{ height: '100vh' }} onMouseMove={handleMouseMove}>
      {render(position)}
    </div>
  );
}

function App() {
  return (
    <MouseTracker render={({ x, y }) => (
      <h1>Mouse position: ({x}, {y})</h1>
    )} />
  );
}
Enter fullscreen mode Exit fullscreen mode

5.3. Compound Components

Compound components are a pattern where components work together to manage their state and behavior.

function Tabs({ children }) {
  const [activeTab, setActiveTab] = useState(0);

  return (
    <div>
      <div>
        {React.Children.map(children, (child, index) => (
          <button onClick={() => setActiveTab(index)}>
            {child.props.title}
          </button>
        ))}
      </div>
      {React.Children.map(children, (child, index) =>
        index === activeTab ? child : null
      )}
    </div>
  );
}

function Tab({ children }) {
  return <div>{children}</div>;
}

function App() {
  return (
    <Tabs>
      <Tab title="Tab 1">Content 1</Tab>
      <Tab title="Tab 2">Content 2</Tab>
      <Tab title="Tab 3">Content 3</Tab>
    </Tabs>
  );
}
Enter fullscreen mode Exit fullscreen mode

5.4. Custom Hooks

Custom hooks allow you to encapsulate logic and reuse it across different components.

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

  const increment = () => setCount(count + 1);
  const decrement = () => setCount(count - 1);

  return { count, increment, decrement };
}

function Counter() {
  const { count, increment, decrement } = useCounter();

  return (
    <div>
      <p>{count}</p>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

6. Optimizing Performance

6.1. Lazy Loading Components

Lazy loading helps improve performance by splitting your code into smaller chunks that are loaded as needed.

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

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

6.2. Code Splitting with React.lazy and Suspense

Code splitting can be achieved using React.lazy and Suspense, allowing parts of your app to load only when needed.

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

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

6.3. Memoizing with React.memo

React.memo can be used to prevent unnecessary re-renders of components that do not change.

const MemoizedComponent = React.memo(function MyComponent({ value }) {
  console.log('Rendered');
  return <div>{value}</div>;
});
Enter fullscreen mode Exit fullscreen mode

6.4. Using React.PureComponent for Performance Gains

React.PureComponent is similar to React.Component, but it performs a shallow comparison of props and state to prevent unnecessary re-renders.

class MyComponent extends React.PureComponent {
  render() {
    return <div>{this.props.value}</div>;
  }
}
Enter fullscreen mode Exit fullscreen mode

7. Routing in React

7.1. Basic Routing with React Router

React Router is the most popular library for routing in React applications.

import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom';

function Home() {
  return <h2>Home</h2>;
}

function About() {
  return <h2>About</h2>;
}

function App() {
  return (
    <Router>
      <nav>
        <Link to="/">Home</Link>
        <Link to="/about">About</Link>
      </nav>

      <Switch>
        <Route exact path="/" component={Home} />
        <Route path="/about" component={About} />
      </Switch>
    </Router>
  );
}
Enter fullscreen mode Exit fullscreen mode

7.2. Nested Routes

You can define nested routes within your application.

function Topics() {
  return (
    <div>
      <h2>Topics</h2>
      <Switch>
        <Route path="/topics/topic1">
          <Topic1 />
        </Route>
        <Route path="/topics/topic2">
          <Topic2 />
        </Route>
      </Switch>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

7.3. Dynamic Routing

Dynamic routing allows you to create routes that accept parameters.

function Topic({ match }) {
  return <h3>Requested Param: {match.params.topicId}</h3>;
}

function Topics() {
  return (
    <div>
      <h2>Topics</h2>
      <ul>
        <li>
          <Link to="/topics/topic1">Topic 1</Link>
        </li>
        <li>
          <Link to="/topics/topic2">Topic 2</Link>
        </li>
      </ul>

      <Switch>
        <Route path="/topics/:topicId" component={Topic} />
      </Switch>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

7.4. Protected Routes

Protected routes are routes that require authentication to access.

function PrivateRoute({ component: Component, ...rest }) {
  const isAuthenticated = false; // Replace with your auth logic

  return (
    <Route
      {...rest}
      render={(props) =>
        isAuthenticated ? (
          <Component {...props} />
        ) : (
          <Redirect to="/login" />
        )
      }
    />
  );
}
Enter fullscreen mode Exit fullscreen mode

8. Testing in React

8.1. Writing Unit Tests with Jest

Jest is a popular testing framework for React applications.

import { render, screen } from '@testing-library/react';
import MyComponent from './MyComponent';

test('renders learn react link', () => {
  render(<MyComponent />);
  const linkElement = screen.getByText(/learn react/i);
  expect(linkElement).toBeInTheDocument();
});
Enter fullscreen mode Exit fullscreen mode

8.2. Testing Components with React Testing Library

React Testing Library is a tool for testing React components in a way that resembles how users interact with them.

import { render, fireEvent } from '@testing-library/react';
import Counter from './Counter';

test('increments counter', () => {
  const { getByText } = render(<Counter />);
  const button = getByText(/increment/i);
  fireEvent.click(button);
  expect(getByText(/count: 1/i)).toBeInTheDocument();
});
Enter fullscreen mode Exit fullscreen mode

8.3. Mocking API Calls

You can mock API calls in your tests to simulate different scenarios.

import { render, screen, waitFor } from '@testing-library/react';
import App from './App';
import fetchMock from 'jest-fetch-mock';

fetchMock.enableMocks();

beforeEach(() => {
  fetch.resetMocks();
});

test('loads and displays data', async () => {
  fetch.mockResponseOnce(JSON.stringify({ data: '12345' }));

  render(<App />);

  expect(screen.getByText('Loading...')).toBeInTheDocument();

  await waitFor(() => screen.getByText('12345'));

  expect(screen.getByText('12345')).toBeInTheDocument();
});
Enter fullscreen mode Exit fullscreen mode

8.4. Snapshot Testing

Snapshot testing ensures that your UI does not change unexpectedly.

import renderer from 'react-test-renderer';
import MyComponent from './MyComponent';

test('renders correctly', () => {
  const tree = renderer.create(<MyComponent />).toJSON();
  expect(tree).toMatchSnapshot();
});
Enter fullscreen mode Exit fullscreen mode

9. Managing Forms in React

9.1. Controlled vs. Uncontrolled Components

Controlled components are those whose form data is handled by the React component's state.

function MyForm() {
  const [value, setValue] = useState('');

  const handleChange = (event) => {
    setValue(event.target.value);
  };

  return <input type="text" value={value} onChange={handleChange} />;
}
Enter fullscreen mode Exit fullscreen mode

Uncontrolled components are those where the form data is handled by the DOM itself.

function MyForm() {
  const inputRef = useRef();

  const handleSubmit = (event) => {
    event.preventDefault();
    alert(inputRef.current.value);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input type="text" ref={inputRef} />
      <button type="submit">Submit</button>
    </form>
  );
}
Enter fullscreen mode Exit fullscreen mode

9.2. Using Formik for Form Management

Formik is a popular library for managing forms in React.

import { Formik, Form, Field } from 'formik';

function MyForm() {
  return (
    <Formik
      initialValues={{ name: '' }}
      onSubmit={(values) => console.log(values)}
    >
      <Form>
        <Field name="name" />
        <button type="submit">Submit</button>
      </Form>
    </Formik>
  );
}
Enter fullscreen mode Exit fullscreen mode

9.3. Validation with Yup

Yup is a JavaScript schema builder for validation and parsing.

import * as Yup from 'yup';

const validationSchema = Yup.object({
  name: Yup.string().required('Name is required'),
});

<Formik
  initialValues={{ name: '' }}
  validationSchema={validationSchema}
  onSubmit={(values) => console.log(values)}
>
  <Form>
    <Field name="name" />
    <ErrorMessage name="name" />
    <button type="submit">Submit</button>
  </Form>
</Formik>;
Enter fullscreen mode Exit fullscreen mode

9.4. Handling Multiple Inputs

You can manage multiple inputs by using dynamic keys in your state.

function MyForm() {
  const [formData, setFormData] = useState({});

  const handleChange = (event) => {
    setFormData({
      ...formData,
      [event.target.name]: event.target.value,
    });
  };

  return (
    <form>
      <input name="firstName" onChange={handleChange} />
      <input name="lastName" onChange={handleChange} />
    </form>
  );
}
Enter fullscreen mode Exit fullscreen mode

10. React and TypeScript

10.1. Adding TypeScript to Your React Project

To add TypeScript to an existing React project, install TypeScript and rename your .js files to .tsx.

npm install --save typescript @types/node @types/react @types/react-dom
Enter fullscreen mode Exit fullscreen mode

10.2. Type Checking with TypeScript

TypeScript allows you to add static types to your React components.

type GreetingProps = {
  name: string;
};

function Greeting({ name }: GreetingProps) {
  return <h1>Hello, {name}</h1>;
}
Enter fullscreen mode Exit fullscreen mode

10.3. Using Interfaces for Props

You can use interfaces instead of types to define the props for your components.

interface GreetingProps {
  name: string;
}

function Greeting({ name }: GreetingProps) {
  return <h1>Hello, {name}</h1>;
}
Enter fullscreen mode Exit fullscreen mode

10.4. Typing State and Hooks

You can type your state and hooks in TypeScript for better type safety.

function Counter() {
  const [count, setCount] = useState<number>(0);

  return (
    <div>
      <p>{count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

11. React and GraphQL

11.1. Fetching Data with Apollo Client

Apollo Client is a popular library for working with GraphQL in React.

import { ApolloClient, InMemoryCache, ApolloProvider, useQuery, gql } from '@apollo/client';

const client = new ApolloClient({
  uri: 'https://example.com/graphql',
  cache: new InMemoryCache(),
});

const GET_DATA = gql`
  query GetData {
    data {
      id
      value
    }
  }
`;

function DataComponent() {
  const { loading, error, data } = useQuery(GET_DATA);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error :(</p>;

  return (
    <ul>
      {data.data.map(({ id, value }) => (
        <li key={id}>{value}</li>
      ))}
    </ul>
  );
}

function App() {
  return (
    <ApolloProvider client={client}>
      <DataComponent />
    </ApolloProvider>
  );
}
Enter fullscreen mode Exit fullscreen mode

11.2. Writing GraphQL Mutations

Mutations in GraphQL are used to modify server-side data.

const ADD_ITEM = gql`
  mutation AddItem($value: String!) {
    addItem(value: $value) {
      id
      value
    }
  }
`;

function AddItem() {
  let input;
  const [addItem, { data }] = useMutation(ADD_ITEM);

  return (
    <div>
      <form
        onSubmit={(e) => {
          e.preventDefault();
          addItem({ variables: { value: input.value } });
          input.value = '';
        }}
      >
        <input
          ref={(node) => {
            input = node;
          }}
        />
        <button type="submit">Add Item</button>
      </form>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

11.3. Using GraphQL Fragments

Fragments allow you to share common fields between multiple queries or mutations.

const ITEM_DETAILS = gql`
  fragment ItemDetails on Item {
    id
    value
  }
`;

const GET_ITEMS = gql`
  query GetItems {
    items {
      ...ItemDetails
    }
  }
  ${ITEM_DETAILS}
`;

const ADD_ITEM = gql`
  mutation AddItem($value: String!) {
    addItem(value: $value) {
      ...ItemDetails
    }
  }
  ${ITEM_DETAILS}
`;
Enter fullscreen mode Exit fullscreen mode

11.4. Handling Errors in GraphQL

Apollo Client provides tools to handle errors in your GraphQL queries and mutations.

function DataComponent() {
  const { loading, error, data } = useQuery(GET_DATA);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error :(</p>;

  return <div>Data loaded successfully!</div>;
}
Enter fullscreen mode Exit fullscreen mode

12. Miscellaneous Tips and Tricks

12.1. Using React.Fragment to Avoid Extra Nodes

Use React.Fragment to group multiple elements without adding extra nodes to the

DOM.

function MyComponent() {
  return (
    <React.Fragment>
      <h1>Hello</h1>
      <p>World</p>
    </React.Fragment>
  );
}
Enter fullscreen mode Exit fullscreen mode

12.2. Using dangerouslySetInnerHTML Safely

dangerouslySetInnerHTML is a React feature that allows you to set HTML directly from a string. Use it cautiously to avoid XSS attacks.

function MyComponent() {
  return <div dangerouslySetInnerHTML={{ __html: 'Hello <strong>World</strong>' }} />;
}
Enter fullscreen mode Exit fullscreen mode

12.3. Conditionally Adding Attributes

You can conditionally add attributes to your JSX elements.

function MyComponent({ disabled }) {
  return <button disabled={disabled ? true : undefined}>Click Me</button>;
}
Enter fullscreen mode Exit fullscreen mode

12.4. Optimizing Performance with React.memo

React.memo is a higher-order component that memoizes your component and only re-renders it when its props change.

const MyComponent = React.memo(function MyComponent({ name }) {
  return <div>Hello, {name}</div>;
});
Enter fullscreen mode Exit fullscreen mode

12.5. Using React.lazy for Code Splitting

React.lazy is a function that lets you render a dynamic import as a regular component. It's useful for code-splitting.

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

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

12.6. Using the Context API for State Management

The Context API is a React feature that lets you pass data through the component tree without having to pass props down manually at every level.

const MyContext = React.createContext();

function MyProvider({ children }) {
  const [state, setState] = useState('Hello World');

  return (
    <MyContext.Provider value={{ state, setState }}>
      {children}
    </MyContext.Provider>
  );
}

function MyComponent() {
  const { state } = useContext(MyContext);

  return <div>{state}</div>;
}
Enter fullscreen mode Exit fullscreen mode

12.7. Using Higher-Order Components (HOCs)

Higher-order components are functions that take a component and return a new component with additional props or functionality.

function withExtraProps(Component) {
  return function (props) {
    return <Component {...props} extra="extra value" />;
  };
}

const MyComponent = withExtraProps(function ({ extra }) {
  return <div>{extra}</div>;
});
Enter fullscreen mode Exit fullscreen mode

12.8. Managing Side Effects with useEffect

The useEffect hook is used to handle side effects in function components, such as fetching data or setting up event listeners.

function MyComponent() {
  useEffect(() => {
    document.title = 'Hello World';
  }, []);

  return <div>Hello World</div>;
}
Enter fullscreen mode Exit fullscreen mode

12.9. Cleaning Up in useEffect

You can return a cleanup function from useEffect to clean up side effects when a component unmounts.

function MyComponent() {
  useEffect(() => {
    const timer = setInterval(() => {
      console.log('Tick');
    }, 1000);

    return () => {
      clearInterval(timer);
    };
  }, []);

  return <div>Check the console</div>;
}
Enter fullscreen mode Exit fullscreen mode

12.10. Handling Errors Gracefully

You can handle errors gracefully in React by using error boundaries.

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

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

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

    return this.props.children;
  }
}

function MyComponent() {
  if (Math.random() > 0.7) {
    throw new Error('Oops!');
  }

  return <div>Hello World</div>;
}

function App() {
  return (
    <ErrorBoundary>
      <MyComponent />
    </ErrorBoundary>
  );
}
Enter fullscreen mode Exit fullscreen mode

13. Conclusion

React is a powerful library for building modern web applications, offering a flexible component-based architecture. Whether you're building simple UI components or complex applications, understanding these core concepts and techniques will help you create scalable and maintainable projects. Happy coding!

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .