Skip to main content

What is React?

ReactJS, commonly referred to as React, is an open-source JavaScript library for building user interfaces or UI components. Maintained by Facebook and a community of individual developers and companies,

React can be used as a base in the development of single-page or mobile applications. It's designed to be declarative, making it painless to create interactive UIs by designing simple views for each state in your application, and React will efficiently update and render just the right components when your data changes.

Declarative views make your code more predictable and easier to debug. A key feature of React is the concept of components, which are like JavaScript functions that return HTML elements via a JSX syntax. Components can be composed into larger components that manage their own state, then formatted into complex user interfaces without compromising the code's readability or maintainability.

React also excels in reusability with components, one-way data flow, virtual DOM that improves the performance of the app, and a rich ecosystem with tools and extensions. React has gained immense popularity among developers due to its simplicity, expressive capabilities, and its ability to be paired effectively with other libraries or frameworks.

React is Declarative, It means 'Just tell me what to do, I will worry about how I get it done'. React is Composable, It means small pieces that we can put together to make something big.

Here are some key points and features of React:

  1. Component-Based: React allows developers to build encapsulated components that manage their own state. These components can then be composed to make complex UIs. Each component can be thought of as a self-contained unit with its own logic and presentation.

  2. Declarative: React makes it painless to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes.

  3. Virtual DOM: One of React's distinctive features is the virtual DOM. Instead of directly updating the actual DOM every time there's a change, React creates a virtual representation of the DOM. When there's a change, React compares the new virtual DOM with the previous one and calculates the most efficient way to update the actual DOM. This process is known as "reconciliation."

  4. JSX: React introduces JSX, which allows developers to write UI structures in a way that resembles HTML but within JavaScript. While JSX is optional, it is widely adopted due to its expressiveness and clarity.

  5. Unidirectional Data Flow: React follows a unidirectional data flow (or one-way data binding). This means that when designing a React application, you often nest child components within parent components. The parent passes data to the child via "props", and the child communicates back to the parent through functions passed as props.

  6. Hooks: Introduced in React 16.8, hooks allow developers to use state and other React features without writing a class component. Some of the common hooks include useState, useEffect, and useContext.

  7. Context: React provides a way to pass data through the component tree without having to pass props down manually at every level, known as Context.

  8. Performance Optimization: React provides various ways to optimize performance, such as shouldComponentUpdate, PureComponent, and the memo function for functional components.

  9. Ecosystem: React has a rich ecosystem. While React itself focuses on UI components, the community has developed libraries for state management (e.g., Redux, MobX), routing (e.g., React Router), and many other functionalities.

  10. Platform Agnostic: While React was initially developed for web, with the introduction of React Native, developers can now write mobile applications for iOS and Android using a similar React paradigm.

React has grown in popularity since its introduction, mainly because of its focus on building reusable components, its performance optimizations, and its flexibility to integrate with various backends and platforms. Many large-scale applications and websites, including Facebook, Instagram, Airbnb, and Netflix, leverage React in their front-end architectures.

JSX​

JSX stands for JavaScript XML. It is a syntax extension for JavaScript, recommended by the React team, which effectively allows you to write HTML structures in the same file as JavaScript code. This co-location can make it more convenient to develop UI components since the markup and the corresponding logic that describes how the UI should behave are contained within a single file.

Under the hood, JSX is not understood by browsers and requires a transpilation process, typically done by Babel, to convert the JSX into standard JavaScript objects that browsers can understand. This process includes converting tags into React.createElement calls which create the virtual DOM objects that React uses to diff against the actual DOM for efficient updates.

The syntax of JSX is similar to HTML with a few key differences. It allows you to embed expressions inside curly braces {} so you can insert JavaScript variables or logic into the rendered output. Also, since it's JavaScript, JSX is camelCased, so attributes like class and for in HTML are renamed to className and htmlFor in JSX to avoid conflicts with JavaScript reserved words.

Here's a simple example of JSX:

const element = <h1>Hello, world!</h1>;

In this snippet, element is not a string nor HTML. It's called a JSX element, and it represents a DOM element. When a JSX element is rendered, React creates a virtual DOM element (a lightweight representation of an actual DOM element). The virtual DOM then goes through a reconciliation process where it is compared with the previous virtual DOM snapshot and only updates the real DOM with what has actually changed, which is a more efficient approach than updating the entire DOM every time a single element changes.

Pure Functions​

In React, a pure function is a component function that adheres to the concept of pure functions in functional programming. This means that the function:

  1. Always returns the same result if given the same arguments. It doesn’t rely on or affect any external state or variables that could cause it to return different results on subsequent calls with the same props.
  2. Does not cause side effects. It doesn’t modify any external variables, perform I/O operations, or cause any observable changes in the state outside of the function scope (such as mutating props or the state of a parent component).

A pure function component in React might look like this:

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

Each time you call this component with the same props.name, it will always return the exact same output without changing or relying on any other state. Additionally, the component doesn’t modify the props or interact with any global state, making it predictable and easy to test.

React also provides a React.PureComponent class which is used to create class components that only re-render when their props or state change. PureComponent implements shouldComponentUpdate() with a shallow prop and state comparison to determine if re-rendering is needed. This can help prevent unnecessary renders and improve performance for components that receive complex objects as props and have a state that changes infrequently.

However, it's important to note that React.PureComponent's shallow comparison can lead to missed updates if the state or props are mutated in place rather than returning new objects with updated values. Hence, immutability is a key aspect when working with pure components.

Higher Order Functions​

In React, higher-order functions are not different from the general concept of higher-order functions in JavaScript. A higher-order function is a function that either takes a function as an argument or returns a function as a result, or both.

Here's how higher-order functions are commonly used in React:

  1. Taking a function as an argument: This is typically seen in event handling or in lifecycle methods where you pass a callback function. For example, the array method .map() is often used in React to transform an array of data into an array of components.

    // This is a higher-order function because it takes a function as an argument
    const List = ({ items }) => (
    <ul>
    {items.map((item) => <li key={item.id}>{item.name}</li>)} // `.map()` is a higher-order function
    </ul>
    );
  2. Returning a function as a result: This pattern is commonly used in the context of higher-order components (HOCs), which are functions that take a component and return a new component with additional props or behaviors.

    // A simple HOC that adds extra props to the wrapped component
    const withExtraProps = (WrappedComponent) => {
    return class extends React.Component {
    render() {
    const newProps = {
    extraProp: 'extraValue'
    };
    return <WrappedComponent {...this.props} {...newProps} />;
    }
    };
    };

In the case of higher-order components, they are particularly useful for reusing component logic, such as connecting to a Redux store, handling state, or applying styles.

React's functional programming paradigm, where functions are used to encapsulate and manage side-effects, makes higher-order functions a powerful tool in the toolkit of a React developer. They help in abstracting and structuring the code in a clear, concise, and reusable manner.

Functional Vs Class Components​

Functional components and class components are two ways of writing components in React, each with its own use cases and benefits.

Functional Components:

  • Introduced in React as Stateless Functional Components, they were initially functions that took props as an argument and returned JSX.
  • With the introduction of Hooks in React 16.8, functional components can now manage state, side effects, context, refs, and more, which were previously only possible with class components.
  • They tend to be simpler and smaller than class components, making them easier to read and test.
  • Often result in less code and better performance, especially after optimizations in React 16.6 with React.memo for memoization.
  • Hooks provide a more intuitive way to handle state and lifecycle methods by allowing you to use them in functional components without changing their component type.

Class Components:

  • They have been around since the early days of React.
  • Class components offer more features than functional components, such as state management and lifecycle methods.
  • They tend to be more verbose than functional components.
  • Require the use of this to access props and state, which can be confusing for some developers.
  • Can use error boundaries to catch JavaScript errors anywhere in their child component tree.

Which One to Use? There is no definitive answer to which type of component is "best" to use; it often comes down to personal preference, project requirements, and team conventions. However, the React team now recommends using functional components with hooks for new components:

  • Simplicity: Functional components are simpler to write and understand because they are just JavaScript functions without the complexity of this context, binding event handlers, or remembering to extend React.Component.
  • Hooks: With hooks, functional components have virtually the same capabilities as class components.
  • Tree Shaking: Functional components are more amenable to automatic code elimination, making your bundle size smaller.
  • Hot Reloading: Functional components can work better with hot reloading.
  • Conciseness: They can be less verbose, which makes them more readable and maintainable.

In existing projects, you might still see class components, especially if they were written before the introduction of hooks. While there's no need to rewrite existing class components into functional ones, many developers prefer writing new components as functional components due to their simplicity and the power of hooks.

Why we need hooks in react​

Hooks in React are a feature that allows you to use state and other React features without writing a class. They were introduced in React 16.8 to solve a number of problems developers encountered with class components. Here's why hooks are beneficial and have become widely adopted in the React community:

  1. Function Component Enhancements: Prior to hooks, function components were known as "stateless" and could not use many features that were exclusive to class components, like state and lifecycle methods. Hooks provide a way to add these capabilities to function components.

  2. Reusing Stateful Logic: Before hooks, patterns like render props and higher-order components were the primary means of reusing stateful logic between components, which could lead to unwieldy component hierarchies. Hooks allow you to extract stateful logic from a component without changing its hierarchy, which makes the logic easier to share and reuse.

  3. Simplified Code: Class components require understanding of 'this' keyword, binding event handlers in constructors, and more boilerplate code. Hooks allow you to work without classes, which can simplify your code and make it easier to understand and maintain.

  4. Organized Side Effects: Managing lifecycle methods like componentDidMount, componentDidUpdate, and componentWillUnmount in class components often leads to spreading related logic across multiple methods. Hooks allow you to group side effects in a more organized way, using useEffect and other similar hooks.

  5. Avoid this Keyword Confusion: 'this' in JavaScript can be confusing, especially for beginners. Since functional components with hooks don't use this, it can make the learning curve less steep.

  6. Optimized Performance: Hooks like useMemo and useCallback help to optimize performance by memoizing values and callbacks, thus preventing unnecessary re-renders.

  7. Concurrent Mode Compatibility: Hooks are designed to ensure compatibility with concurrent mode, a set of new features that help React apps stay responsive and gracefully adjust to the user’s device capabilities and network speed.

  8. Better Adoption Strategy: You can start using hooks in your new components without rewriting existing code. React doesn’t offer a “hooks-only” mode, so you don’t have to commit to using hooks for an entire project, allowing gradual adoption.

  9. Easier to Test: Functions are generally easier to test than classes. Since hooks are just functions, they can simplify the testing process.

  10. Community and Ecosystem: The React community has embraced hooks, leading to a rich ecosystem of custom hooks that you can incorporate into your applications to solve common problems.

In summary, hooks offer a more powerful, flexible, and simpler way to build React components, facilitating easier code reuse, better code organization, and alignment with modern JavaScript practices.

Hooks​

useEffect​

**use **​

useCallback​

useContext​

useEffect​

useId​

useMemo​

useReducer​

useRef​

useState​

Why we need useState​

The useState hook in React is essential for maintaining state in a functional component. In traditional JavaScript, assigning values to variables and using them directly will not provide the reactivity that React's state system offers. Here’s why useState is crucial:

  1. State Persistence: Without useState, the state of your component would not persist between re-renders. Every time a component re-renders, all the variables inside it are re-initialized. useState provides a way to persist state values through the component's lifecycle.

  2. Reactivity: React's reactivity system is built around the concept of state. When you use useState, React knows that when the state changes, it needs to re-render the component to reflect those changes in the UI. Regular variables don't have this capability; changing their value doesn't trigger a component update.

  3. Immutable State: In React, states are meant to be immutable. You do not directly modify the state but rather use setter functions provided by useState. This approach ensures that React can efficiently determine when and what to re-render.

  4. Hooks Trigger Re-renders: The setter function returned by useState is what you use to update the state. When you call this function, React schedules a re-render of the component, ensuring the UI is up to date with the latest state.

  5. Batched Updates: React batches state updates for performance optimizations. If you have multiple useState setters called in a single event handler, React will batch them and update the state in a single pass to avoid unnecessary re-renders.

  6. Functional Updates: useState allows for functional updates, where you can pass a function to the setter that will receive the previous state and return an updated value. This is particularly useful for updates that depend on the current state.

  7. State Initialization Logic: useState lets you provide an initial state, which can be a simple value or the result of a function call for lazy initialization. This is useful when the initial state is computationally expensive to derive.

Using useState is about more than just holding values; it's about integrating with React's lifecycle and rendering processes. It is the fundamental mechanism by which React is able to efficiently update the DOM to match your application's state. Without it, you would lose out on the benefits of React's declarative UI paradigm.

useTransition​

Components​

Fragment​

In React, a Fragment is a component that allows you to group a list of children without adding extra nodes to the DOM. This is particularly useful when rendering multiple elements in a component that expects a single root element, such as when creating a list or a table, but you don't want to introduce an extra parent element like a div that would affect the layout or styling.

Why Use Fragments?

  • DOM Bloat: Adding extra div elements can lead to a bloated DOM tree, which can affect performance and complicate CSS styling.
  • Table Elements: When rendering components within a <table>, you cannot wrap adjacent rows in a div as it would break the table structure. Fragments solve this by allowing you to group a list of rows without adding an extra element.
  • Semantic HTML: Using unnecessary div elements can make the HTML less semantic. Fragments avoid this by not contributing any output to the actual DOM structure.

How to Use Fragments? There are two ways to declare a Fragment in React:

  1. Short Syntax: You can use the empty tag <> ... </> to wrap multiple elements.

    return (
    <>
    <ChildA />
    <ChildB />
    <ChildC />
    </>
    );
  2. Named Syntax: If you need to pass a key prop for rendering a list, you need to use the longer React.Fragment syntax.

    return (
    <React.Fragment>
    <ChildA />
    <Child.B />
    <Child.C />
    </React.Fragment>
    );

For keyed fragments, you would use React.Fragment because the short syntax does not support keys or attributes.

return data.map(item => (
<React.Fragment key={item.id}>
<ColumnA data={item} />
<ColumnB data={item} />
</React.Fragment>
));

In essence, Fragments let you wrap multiple elements without adding an extra node to the DOM, keeping your rendered output cleaner and more efficient.

Strict Mode​

In React, StrictMode is a development tool that helps you write better code by automatically checking for potential problems in your application. It does not render any visible UI but activates additional checks and warnings for its descendants in the component tree.

Here's what StrictMode does:

  1. Identifying Components with Unsafe Lifecycles: It helps identify usage of legacy lifecycle methods that are unsafe and will not work in future versions of React, such as componentWillMount, componentWillReceiveProps, and componentWillUpdate.

  2. Warning About Legacy String Ref API: It warns if you're using the old string ref API, which might have issues and is considered legacy. The callback ref or createRef API is preferred.

  3. Detecting Unexpected Side Effects: It detects side effects in the render phase. The render method should be pure, meaning it does not modify state and returns the same output given the same inputs. StrictMode helps ensure this by intentionally double-invoking the following methods:

    • Class component constructor, render, and shouldComponentUpdate methods
    • Class component static getDerivedStateFromProps method
    • Function component bodies
    • State updater functions (the first argument to setState)
    • Functions passed to useState, useMemo, or useReducer
  4. Detecting Legacy Context API: It warns about the usage of the old context API, which is deprecated in favor of the new context API (React.createContext).

  5. Helping with ForwardRef and Memo Usage: It checks components that use forwardRef and memo to ensure they pass the ref and props correctly.

  6. Warning About findDOMNode: It warns about the usage of findDOMNode, which is deprecated and should be avoided in favor of ref callbacks or React.createRef.

  7. Detecting Unexpected Mutations: It helps identify potential problems with mutation of props (which is not allowed in React) and unexpected side effects in the render phase.

To use StrictMode, you can wrap your components with it, like this:

import React from 'react';

function App() {
return (
<React.StrictMode>
<MyComponent />
</React.StrictMode>
);
}

StrictMode currently helps with:

  • Identifying components with unsafe lifecycles
  • Warning about legacy string ref API usage
  • Warning about deprecated findDOMNode usage
  • Detecting unexpected side effects
  • Detecting legacy context API

It's important to note that StrictMode checks are run in development mode only; they do not impact the production build. This tool greatly assists in preparing your codebase for the future and ensuring it adheres to the best practices recommended by the React team.

Suspence​

Suspense is a component in React that lets your components “wait” for something before rendering. It's used to handle asynchronous operations like data fetching, code splitting, or any task that might take some time to complete. Suspense allows you to specify a loading state (fallback) for the part of the component tree until the awaited operations are finished.

Here are key points about Suspense:

  1. Lazy Loading Components: It works well with React.lazy for code splitting. You can dynamically import a component with React.lazy, and Suspense will handle the loading state while the component is being downloaded.

  2. Data Fetching: It can be used to wait for data to be fetched before rendering the components that depend on that data. This can help avoid a waterfall of loading states and provide a smoother user experience.

  3. Fallback UI: Suspense accepts a fallback prop that takes any React elements you want to render while waiting for the child components to be ready. This is commonly a spinner or a loading indicator.

  4. Error Handling: When combined with error boundary components, Suspense can help manage loading states and errors gracefully.

Example of using Suspense with React.lazy:

import React, { Suspense } from 'react';
const OtherComponent = React.lazy(() => import('./OtherComponent'));

function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<OtherComponent />
</Suspense>
</div>
);
}

In this example, OtherComponent is being lazy-loaded, and Suspense is used to show a loading indicator until OtherComponent is ready to be rendered.

Suspense for data fetching is an experimental feature and it works with libraries that support Suspense-like APIs, such as Relay.

It's important to note that Suspense is not a data fetching library or a router, but a mechanism that libraries can leverage to provide a better integration with concurrent rendering in React.

As of my last update, Suspense for data fetching is still experimental, and while it can be used with React’s experimental Concurrent Mode, it may not be ready for production use in all cases. However, Suspense for code splitting (with React.lazy) is stable and can be used in production.

Profiler​

The Profiler is a React component that measures the performance of rendering. It can be used to gather information about the time it takes for React to render components. The primary purpose of the Profiler is to identify performance bottlenecks in React applications and provide insights into optimizing them.

Key aspects of the Profiler component:

  1. Granular Performance Metrics: It collects timing information about each component that is rendered as part of a profiling session. This includes the render phase, commit phase, and effects.

  2. Nested Usage: You can wrap Profiler around individual components or entire subtrees to measure performance in different parts of your application.

  3. Custom onRender Callback: The Profiler accepts an onRender callback as a prop, which is called each time the component within the profiler tree renders. This callback provides the following parameters:

    • id - The "id" prop of the Profiler tree that has just committed.
    • phase - Either "mount" (if the tree just mounted) or "update" (if it re-rendered).
    • actualDuration - Time spent rendering the committed update.
    • baseDuration - Estimated time to render the entire subtree without memoization.
    • startTime - When React began rendering this update.
    • commitTime - When React committed this update.
    • interactions - The set of interactions belonging to this update.
  4. DevTools Integration: When using React DevTools, profiling information is made visible in the "Profiler" tab, providing a visual representation of rendering times and allowing you to analyze rendering performance.

Here's an example of how to use the Profiler component:

import React, { Profiler } from 'react';

function onRenderCallback(
id, // the "id" prop of the Profiler tree that has just committed
phase, // either "mount" (if the tree just mounted) or "update" (if it re-rendered)
actualDuration, // time spent rendering the committed update
baseDuration, // estimated time to render the entire subtree without memoization
startTime, // when React began rendering this update
commitTime, // when React committed this update
interactions // the Set of interactions belonging to this update
) {
// Aggregate or log render timings...
}

function MyComponent() {
return (
<Profiler id="MyComponent" onRender={onRenderCallback}>
{/* ...components go here... */}
</Profiler>
);
}

It's important to use the Profiler component sparingly in production. It's primarily intended for development use, as it may add some additional overhead to the rendering process. However, this overhead is generally small and typically won't have a significant impact on the user experience.

Client APIs​

In React 18 and later, new APIs were introduced for rendering and hydrating apps, providing more control over the timing of renders and supporting concurrent features. Two of these APIs are createRoot and hydrateRoot.

createRoot:

The createRoot method is used to create a root for a React application. It replaces the old ReactDOM.render method and is the entry point for the new concurrent features in React. When you create a root, you can control when the React component tree is rendered. With createRoot, you can take advantage of concurrent rendering, which allows React to prepare multiple versions of the UI at the same time.

Here's how you might use createRoot:

import { createRoot } from 'react-dom/client';

const container = document.getElementById('app');
const root = createRoot(container); // create a root.
root.render(<App />); // initial render

hydrateRoot:

The hydrateRoot method is used when you have a server-rendered application and you want to "hydrate" the HTML with React. This means that React will attach event listeners to the existing markup without re-rendering everything. This process allows for a faster initial load time and a smoother user experience, as the user can see and interact with the server-rendered content immediately, while React is loading in the background.

Here's an example of using hydrateRoot:

import { hydrateRoot } from 'react-dom/client';

const container = document.getElementById('app');
const root = hydrateRoot(container, <App />);

In this example, React will attach to an existing server-rendered DOM marked up with the same component tree as <App /> and make it interactive.

Both createRoot and hydrateRoot are part of the React DOM Client API and provide more flexibility and performance benefits compared to the legacy ReactDOM.render and ReactDOM.hydrate methods. With these APIs, React 18 enables out-of-the-box improvements like automatic batching of updates, which can lead to smoother and more responsive UIs.

Server APIs​

renderToPipeableStream​

The renderToPipeableStream function is part of the React Server API, introduced in React 18 to support server-side rendering (SSR) with streaming. This API allows you to generate HTML on the server and stream it to the client as the components are rendered, rather than waiting for the entire component tree to finish rendering before sending any HTML. This can significantly improve time to contentful paint (TCP) and interactivity for users on slow networks.

Here’s a high-level overview of how renderToPipeableStream works:

  1. The server starts rendering components asynchronously.
  2. As soon as the first bits of HTML are ready, they are sent to the client.
  3. The client can start parsing and rendering content as it arrives.
  4. Non-critical components can be intentionally delayed to let more important content stream first, using the startTransition API.

Here is an example of how you might use renderToPipeableStream:

import { renderToPipeableStream } from 'react-dom/server';

const app = <App />; // Your React application component
const response = /* ... */; // Node.js HTTP server response object

const stream = renderToPipeableStream(app, {
onShellReady() {
// The HTML for the "shell" of your application is ready to be sent to the client.
response.statusCode = 200; // OK status
response.setHeader('Content-type', 'text/html');
stream.pipe(response);
},
onShellError(err) {
// Something went wrong before we could complete the shell.
// Send a 500 error and a fallback version of the app that doesn't require JS to render.
response.statusCode = 500; // Internal Server Error
response.send(/* ... */);
},
onAllReady() {
// The entire app is ready and can be streamed.
// This could be useful for preloading or caching strategies.
},
onError(err) {
// There was an error during the streaming rendering process.
console.error(err);
},
});

This function is useful for scenarios where you want to improve perceived performance by streaming the initial HTML of the page to the browser as quickly as possible, allowing the content to be viewed and indexed while the rest of the page's content continues to load and render on the server.

renderToPipeableStream is part of the server rendering improvements in React 18 that enable streaming SSR. It is designed to be used with React's Suspense feature, which lets you "suspend" rendering of non-critical components while waiting for data to become available. This means you can stream the most important content to the user first, enhancing the user experience, especially on slower networks or devices.

renderToReadableStream​

renderToReadableStream is an experimental API in React 18 aimed at server-side rendering (SSR) for environments that support the WHATWG Streams API, like Deno and newer versions of Node.js. It is similar to renderToPipeableStream but tailored for the ReadableStream interface provided by the Streams API.

This API allows server-side React rendering to be streamed to the client incrementally, which can improve performance by sending the content as it's generated, rather than waiting for the entire render to complete.

Here’s a conceptual overview of how renderToReadableStream works:

  1. The server begins rendering the React component tree.
  2. The rendering process yields HTML incrementally, which is pushed into a ReadableStream.
  3. The ReadableStream can be directly manipulated or piped to a client response in supported server environments, allowing chunks of HTML to be transmitted to the browser as they become available.
  4. The browser can start displaying content as soon as it receives the first chunk, improving time to first paint and interactivity.

However, as of my last update, this API was still experimental and was not part of the stable React release. This means that its behavior and availability could change, and it may not be recommended for production environments without careful testing.

For an environment like Node.js where renderToReadableStream would be applicable, you might expect to use it in a similar way to renderToPipeableStream, but the actual usage could differ based on the final API design and the environment's support for streams.

Developers interested in using this API should refer to the official React documentation or React 18 release notes for the latest and most accurate guidance, as well as code examples and best practices.

Directives​

use client​

'use client' is needed only if you’re using React Server Components or building a library compatible with them.

use server​

'use server' is needed only if you’re using React Server Components or building a library compatible with them.

ReactJS Book​

Please click the below link for more details.

Ref: Learn React

Ref: React Router