Component Nesting in React

export default function ParentComponent(props) {
  function InnerComponent() {
    // ...
  }

  return (
    <>
      <InnerComponent />
    </>
  );
}

As you can see, InnerComponent is inside ParentComponent–this is component nesting. This may seem convenient to code, but it has some problems

  1. you can’t export InnerComponent & ParentComponent is lesser re-usable.
  2. Performance issue–InnerComponent will be recreated on each render of ParentComponent

You can create a seperate module for InnerComponent or just write it outside ParentComponent

function InnerComponent(props) {
  return (
    // ...
  );
}

export default function ComponentTwo(props) {
  return (
    <>
      <InnerComponent />
    </>
  );
}

How to render HTML inside react?

You can use dangerouslySetInnerHTML prop to render HTML in React. It is used to set HTML directly from React. You should be careful while using this property as it can cause XSS attacks.

what could be the reasons for unnecessary re-renders in react?

Unnecessary re-renders in components can occur due to several reasons, and it’s important to optimize your code to minimize them for better performance.

Here are some common reasons for unnecessary re-renders in functional components:

  • Using inline functions in JSX props: If you pass an inline function as a prop to child components, those components will get re-rendered every time the parent component re-renders. This is because a new function is created on every render. You can optimize this by using useCallback hook to memoize the function.
  • Using useState hook with objects: If you use useState hook with objects, you need to make sure that you are not mutating the object. If you mutate the object, React will not be able to detect the change and will not re-render the component. You can optimize this by using useReducer hook instead of useState hook.
  • Using useEffect hook without dependencies: If you use useEffect hook without dependencies, it will run on every render. You can optimize this by passing an empty array as the second argument to useEffect hook.
  • Parent Component Re-renders: If a parent component re-renders, all its child components will also re-render. You can optimize this by using React.memo to memoize the child component where possible.
  • Global State Changes: If you use global state management libraries like Redux, MobX, etc., and the global state changes, all the components that use that state will re-render. You can optimize this by using useSelector hook to select only the state that you need in a component.
  • Misusing Context: If you use Context API to pass data to child components, and the data changes, all the child components will re-render. You can optimize this by using useContext hook to select only the data that you need in a component.

You can also use React.StrictMode to detect potential problems in your code that could cause unnecessary re-renders.

what is useTransition hook

useTransition hook allows you to mark certain updates as transitions so they can be deprioritized, allowing other, more urgent updates to be processed first. This ensures that the UI remains responsive during updates that might take some time.

import { useTransition, useState } from "react";
import { Posts } from "./Posts";
import { Home } from "./Home";
import { Contact } from "./Contact";

export function App() {
  const [isPending, startTransition] = useTransition();
  const [page, setPage] = useState("home");

  function changePage(newPage: string) {
    startTransition(() => {
      setPage(newPage);
    });
  }

  return (
    <>
      <button onClick={() => changePage("home")}>Home</button>
      <button onClick={() => changePage("posts")}>Posts</button>
      <button onClick={() => changePage("contact")}>Contact</button>
      <hr />
      {isPending && <div>Loading...</div>}
      {page === "home" && <Home />}
      {page === "posts" && <Posts />}
      {page === "contact" && <Contact />}
    </>
  );
}
export function Home() {
  return <div>Home</div>;
}
export function Contact() {
  return <div>Contact</div>;
}

Posts component is artificially delayed by 500ms to emulate extremely slow code.

export function Posts() {
  const items = [];
  for (let i = 0; i < 500; i++) {
    items.push(<SlowPost key={i} />);
  }
  return <ul>{items}</ul>;
}

function SlowPost() {
  const startTime = performance.now();
  while (performance.now() - startTime < 1) {
    // Do nothing for 1 ms per item to emulate extremely slow code
  }

  return <li>Post</li>;
}

Now when you click on the Posts button, you’ll notice that the UI remains responsive and you can still switch to other pages while the posts are loading. Try removing the startTransition wrapper around setPage in changePage to see the difference.

What is the purpose of flushSync in React?

The flushSync function in React is used to flush updates synchronously. It schedules updates to be performed inside a high-priority task, ensuring that the updates are executed immediately and synchronously before returning control to the caller.

import { flushSync } from "react-dom";

flushSync(callback);

This is useful in situations where you need the DOM to be updated immediately, such as for measurements or to ensure synchronous rendering. However, excessive use of flushSync can lead to degraded performance, so it should be used judiciously.

How to render React components as static HTML string?

The renderToString function in React is part of the react-dom/server package and is used to render React components on the server-side to a static HTML string. It is commonly used for server-side rendering (SSR) in React.

Can you use hooks in Server Components?

No, hooks are not supported in Server Components. Hooks are a client-side feature and are not supported in Server Components. However, you can use hooks in client components and import them into Server Components.

What is Hydration in React?

Hydration is the process of using client-side JavaScript to add interactivity to the markup generated by the server. When you use server-side rendering, the server returns a static HTML representation of the component tree. Once this reaches the browser, in order to make it interactive, React “hydrates” the static content, turning it into a fully interactive application.

How do you investigate a slow React app and identify performance bottlenecks?

There are many reasons why an app might be slow. It could be due to a slow network, a slow backend, or a slow client. It could also be due to a memory leak, unnecessary re-renders, or large bundle sizes.

Here are some tips to help you investigate and fix performance issues:

Use the React DevTools Profiler

The React DevTools Profiler helps you visualize how components render and identify costly renderings. It can also help you identify unnecessary re-renders.

Check for Unnecessary Renders

Ensure that components don’t render more often than needed. Be clear about the useEffect dependencies and avoid creating new objects or arrays every render, as these can trigger unnecessary child component renders. Tools like why-did-you-render can help spot unnecessary re-renders.

Analyze Bundle Size

Use your production build to analyze your bundle size. Tools like webpack-bundle-analyzer or source-map-explorer can help you see if large libraries or unused code is slowing down the initial load.

Optimize Images & Assets

Ensure images are appropriately sized and use modern formats. Also, consider using CDNs for assets that don’t change often.

Lazy Load Components

Use lazy() and dynamic imports to split your bundle and load components only when they’re needed. This can help reduce the initial load time.

Check Network Requests

Slow API calls or fetching large amounts of data can affect performance. Optimize your backend, paginate data, or cache results. You can also use tools like @tanstack/react-query or swr to help manage data fetching and caching.

Use Production Build for Testing

Ensure you’re testing the performance on a production build, as development builds are often slower due to extra checks and logs.

Regularly profiling and monitoring your app can help you spot and fix performance issues before they become significant problems. You can use tools like Lighthouse or Calibre to monitor your app’s performance over time.