Showing posts with label react. Show all posts
Showing posts with label react. Show all posts

Monday, 3 February 2025

Understanding React Component Remounting: How Changing the key Prop Triggers Remounting?

 

In React, when the key prop of a component changes, React will remount that component rather than just re-render it.

 

Let's get a quick glance on the mounting, rendering, re-rendering, and remounting to clarify how components are created, updated, and reinitialized.

 

1. Mounting

Mounting is the process when a component is created and added to the DOM for the first time. This happens the very first time a component is rendered in the application.

 

During mounting:

 

·      The component’s initial state is set (if using useState or this.state in class components).

·      Lifecycle methods in class components, like componentDidMount, are called.

·      Hooks in functional components, like useEffect(() => {...}, []), are run if they’re specified with an empty dependency array.

 

Example: If you have a UserProfile component that appears when you open a page, it is mounted the first time it’s displayed.

 

2. Rendering

Rendering is the process of creating the component's UI based on its state and props. Rendering happens during both mounting and updating phases, and it doesn’t necessarily mean there’s a visible change in the DOM each time.

 

·      In each render, React evaluates the JSX and generates a virtual representation of the DOM.

·      If there are changes, React uses the virtual DOM to update only the necessary parts of the real DOM.

 

Note: A render can happen for various reasons, like changes in props or state, but it doesn’t guarantee changes in the DOM unless React detects differences.

 

3. Re-rendering

Re-rendering occurs when React re-runs the component function or class’s render method to update the UI in response to changes in state or props.

 

The component doesn’t mount again; it simply updates.

 

When Re-rendering Occurs:

 

·      State Change: If the component’s state changes, React triggers a re-render.

·      Props Change: If a component receives new props from its parent, React re-renders it.

·      Parent Re-render: If the parent component re-renders, child components usually re-render as well, unless specifically optimized with React.memo or shouldComponentUpdate.

 

Example: A Counter component that updates the displayed count when a button is clicked re-renders each time the count changes.

 

4. Remounting

Remounting is when a component is removed from the DOM and then added back as a new instance. When a component remounts, it goes through the entire mounting process again.

 

·      The component’s state is reinitialized to its initial values.

·      Any useEffect hooks with empty dependencies or lifecycle methods (like componentDidMount) run again.

·      React treats it as a brand-new component instance, meaning any old state or effects from the previous instance are discarded.

 

Following are the common reasons for remounting

·      Key Change: If a component’s key prop changes, React considers it a different component and will remount it. This is often used in lists, where changing the key helps React uniquely identify list items.

 

·      Conditional Rendering: If a component is conditionally rendered (e.g., using a boolean state to toggle its visibility), unmounting and remounting occurs each time it’s hidden and shown again.

 

Whenever a remount happens, the old state is completely forgotten by React.

 

Let’s build an application to demonstrate how updating the key property of a component causes it to remount and completely lose its previous state.

 

Step 1:  Go to the post (Quickly Set Up a React Project with Vite: A Step-by-Step), and set up a React Project react-key-change-explorer.

 

Project structure looks like below.


 

 

Step 2: Create components folder in src folder and define CounterChildApp and CounterParentApp components.

 

CounterChildApp.jsx 

import { useState } from "react";

export default function CounterChildApp({ name }) {
  const [count, setCount] = useState(0);

  console.log("Rendered CounterChildApp.....");

  return (
    <div className="counterChildApp">
      <p className="para">Child Application Name : {name}</p>
      <p className="para">Counter : {count}</p>

      <button
        className="button childCounter"
        onClick={() => {
          setCount((prevCount) => prevCount + 1);
        }}
      >
        Increment Counter
      </button>
    </div>
  );
}

CounterParentApp.jsx

import { useState } from "react";
import CounterChildApp from "./CounterChildApp";

let projectNames = ["Nebula", "Orion", "Nexus", "Lyra", "Zypher"];
let projectIndex = -1;
let keyCount = 0;

function getProjectName() {
  if (projectIndex == projectNames.length - 1) {
    projectIndex = -1;
  }

  projectIndex++;
  return projectNames[projectIndex];
}

function updateKey() {
  keyCount++;
}

export default function CounterParentApp() {
  const [pjtName, setPjtName] = useState(getProjectName());
  const [appKey, setAppKey] = useState(keyCount);

  return (
    <div className="container">
      <div className="demoApp">
        <CounterChildApp name={pjtName} key={appKey} />

        <div className="buttonGroup">
          <button
            onClick={() => {
              setPjtName(getProjectName());
            }}
          >
            Update Name
          </button>

          <button
            onClick={() => {
              updateKey();
              setAppKey(keyCount);
            }}
          >
            Update Key
          </button>
        </div>
      </div>
    </div>
  );
}

Step 4: Create styles folder in src folder and define styles.css file.

 

styles.css

.container{
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    width: 100vw;
    height: 100vh;
}

.demoApp{
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    width: 30vw;
    height: 50vh;
    gap: 10px;
    background-color: rgb(222, 222, 200);
    border-radius: 20px;               /* Rounded corners */
    box-shadow: 0 3px 5px rgba(0, 0, 0, 0.1); /* Subtle shadow for depth */
}

.counterChildApp{
    width: 300px;
    height: 250px;
    display: flex;
    flex-direction: column;
    background-color: rgb(244, 193, 204);
    border-radius: 20px;               /* Rounded corners */
    box-shadow: 0 3px 5px rgba(0, 0, 0, 0.1); /* Subtle shadow for depth */
}

.para,
.childCounter{
    padding: 10px;
    font-size: 1.1em;
}

.button{
    width: 200px;
    height: 60px;
    margin: 10px;
}

.buttonGroup{
    display: flex;
    gap: 10px;
}

Step 5: Build and run the application by executing below commands.

npm install
npm run dev

Open the url ‘http://localhost:5173/’ in browser, you will see below screen.


 

Click on the ‘Increment Counter’ button, you will see that the counter value is changed to 1.


 

Click on the button ‘Update Name’ to change the Application Name.

 


You can observe that Application Name is changed from Orion to Nexus, but the state (counter = 1) is still maintained.

 

Now, click on the button ‘Update Key’.



You can observe that the Counter is reinitialized to 0, it is because the component is remounted.

 

You can download the Application from this link.


Previous                                                    Next                                                    Home

How to handle Undefined Routes in React Router?

We can use wildcard route to match any path that is not explicitly defined.


<Route path="*" element={<NotFound />} />


Above snippet catch all routes for undefined URLs.

 

Follow below step-by-step procedure to build the complete working application.

 

Step 1: Go to the post (Quickly Set Up a React Project with Vite: A Step-by-Step), and set up a React Project ‘handle-undefined-routes’.

 

Project structure looks like below.

 

Step 2: Navigate to the project directory and install react router dom by executing below commands.

cd handle-undefined-routes
npm install react-router-dom

Step 3: Create pages folder in src folder and define Home and Help pages.

 

HomePage.jsx

export default function HomePage() {
  return (
    <>
      <h1>Home Page</h1>
    </>
  );
}

HelpPage.jsx

export default function HelpPage() {
  return (
    <>
      <h1>Help Page</h1>
    </>
  );
}

Step 4: Update App.jsx with below content.

 

App.jsx

import { BrowserRouter, Routes, Route } from "react-router-dom";
import HomePage from "./pages/HomePage";
import HelpPage from "./pages/HelpPage";
import NotFound from "./pages/NotFound";

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<HomePage />}></Route>
        <Route path="/help" element={<HelpPage />}></Route>

        {/* Catch-all route for undefined URLs */}
        <Route path="*" element={<NotFound />} />
      </Routes>
    </BrowserRouter>
  );
}

export default App;

Step 5: Update main.jsx with below content.

 

main.jsx

import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App.jsx";

createRoot(document.getElementById("root")).render(
  <StrictMode>
    <App />
  </StrictMode>
);

Step 6: Build and run the application by executing below commands.

  cd handle-undefined-routes
  npm install
  npm run dev

Open the url ‘http://localhost:5173/’ in browser, you will see home page screen.



Open the url ‘http://localhost:5173/help’, you will see Help Page screen.

 


Open the url ‘http://localhost:5173/abcde’, you will see page not found error.

 


You can download the application from this link.


Previous                                                    Next                                                    Home

Tuesday, 28 January 2025

How to perform Client-Side Redirection in React with the Navigate Component?

Redirection in web applications refers to the process of sending a user from one page or component to another. In the context of single-page applications (SPAs) built with React, client-side redirection allows you to change the view without refreshing the entire page. This enhances the user experience by providing seamless navigation between different parts of the application.

One of the most straightforward ways to achieve client-side redirection is through the Navigate component.

 

What is the Navigate Component?

The Navigate component is part of React Router and is used to programmatically redirect users to a different route. It can be especially useful for redirecting users after a form submission, an authentication check, or any event where you need to change the current URL based on user interaction.

 

Example

<!-- HTML generated using hilite.me --><div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"><pre style="margin: 0; line-height: 125%"><span style="color: #000080; font-weight: bold">if</span> (isLoggedIn) {
    <span style="color: #008800; font-style: italic">// Redirect to dashboard</span>
    <span style="color: #000080; font-weight: bold">return</span> &lt;Navigate to=<span style="color: #0000FF">&quot;/dashboard&quot;</span> /&gt;;
}
</pre></div>

Follow below step-by-step procedure to build the working application.

 

Step 1: Go to the post (Quickly Set Up a React Project with Vite: A Step-by-Step), and set up a React Project ‘client-side-redirection’.

 

Project structure looks like below.



 

Step 2: Navigate to the project directory and install react router dom by executing below commands.

 

cd client-side-redirection
npm install react-router-dom

Step 3: Create pages folder in src folder and define Login and Welcome pages.

 

LoginPage.jsx

import React, { useState } from "react";
import { Navigate } from "react-router-dom";

const LoginPage = () => {
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  const handleLogin = (e) => {
    e.preventDefault();
    // Simulate successful login
    setIsLoggedIn(true);
  };

  if (isLoggedIn) {
    // Redirect to welcome page
    return <Navigate to="/welcome" />;
  }

  return (
    <div>
      <h2>Login Page</h2>
      <form onSubmit={handleLogin}>
        <p>
          <label htmlFor="username">Enter Username : </label>
          <input type="text" placeholder="Username" id="usernane" required />
        </p>

        <p>
          <label htmlFor="password">Enter Password : </label>
          <input type="password" placeholder="Password" required />
        </p>

        <button type="submit">Login</button>
      </form>
    </div>
  );
};

export default LoginPage;

WelcomePage.jsx

export default function WelcomePage() {
  return <>Welcome to the React World!!!!!!!!</>;
}

Step 4: Update App.jsx with below content.

 

App.jsx

import React from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import LoginPage from "./pages/LoginPage";
import WelcomePage from "./pages/WelcomePage";

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<LoginPage />} />
        <Route path="/welcome" element={<WelcomePage />} />
      </Routes>
    </Router>
  );
}

export default App;

Step 5: Update main.jsx with below content.

 

main.jsx

import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App.jsx";

createRoot(document.getElementById("root")).render(
  <StrictMode>
    <App />
  </StrictMode>
);

Step 6: Build and run the application by executing below commands.

  cd client-side-redirection
  npm install
  npm run dev

Open the url ‘http://localhost:5173/’ in browser, you will see a login screen.

 


Enter some random username and password, click on Login button, you will be redirected to welcome page.



You can download the application from below link.

https://github.com/harikrishna553/frontend/tree/main/react/react-router/client-side-redirection

 

You can achieve the same behavior using useNavigate hook as well.

 

LoginPage.jsx

import React, { useState } from "react";
import { Navigate, useNavigate } from "react-router-dom";

const LoginPage = () => {
  const [isLoggedIn, setIsLoggedIn] = useState(false);
  const navigate = useNavigate(); // Correct: use the hook to get the navigate function

  const handleLogin = (e) => {
    e.preventDefault();
    // Simulate successful login
    setIsLoggedIn(true);
  };

  if (isLoggedIn) {
    // Redirect to welcome page
    //return <Navigate to="/welcome" />;
    navigate("/welcome");
    return;
  }

  return (
    <div>
      <h2>Login Page</h2>
      <form onSubmit={handleLogin}>
        <p>
          <label htmlFor="username">Enter Username : </label>
          <input type="text" placeholder="Username" id="usernane" required />
        </p>

        <p>
          <label htmlFor="password">Enter Password : </label>
          <input type="password" placeholder="Password" required />
        </p>

        <button type="submit">Login</button>
      </form>
    </div>
  );
};

export default LoginPage;

 

 

Previous                                                    Next                                                    Home