Prevent child re-rendering in React.js
Asked Answered
Y

1

6

How can I prevent re-rendering of child components in React? Everytime an ID saved in useState is updated at the parent level, the child gets rerendered and loses the selection.

Here is some sample code for the setup:

Parent component:

import React, { useState } from "react";
import ChildComponent from "./ChildComponent";

function ParentComponent() {
  const [selectedProjectId, setSelectedProjectId] = useState("");

  const handleProjectIdChange = (projectId) => {
    setSelectedProjectId(projectId); //<--- this rerenders the ChildComponent which is NOT wanted
  };

  return (
    <div>
      <h1>Parent Component</h1>
      <ChildComponent
        selectedProjectId={selectedProjectId}
        onProjectIdChange={handleProjectIdChange}
      />
      <p>Selected project ID: {selectedProjectId}</p>
    </div>
  );
}

export default ParentComponent;

Child component:

import React, { useState } from "react";

function ChildComponent({ selectedProjectId, onProjectIdChange }) {
  const [projectOptions, setProjectOptions] = useState([
    { id: "1", name: "Project 1" },
    { id: "2", name: "Project 2" },
    { id: "3", name: "Project 3" },
  ]);

  const handleProjectChange = (event) => {
    const projectId = event.target.value;
    onProjectIdChange(projectId);
  };

  return (
    <div>
      <h2>Child Component</h2>
      <select value={selectedProjectId} onChange={handleProjectChange}>
        <option value="">Select a project</option>
        {projectOptions.map((option) => (
          <option key={option.id} value={option.id}>
            {option.name}
          </option>
        ))}
      </select>
    </div>
  );
}

export default ChildComponent;

I tried react.memo, useCallbacks and other methods but nothing worked. I want to prevent useState to udpate the child components everytime the IDs get updated.

Yaroslavl answered 20/4, 2023 at 17:5 Comment(2)
When I place the code to playground, I don't see the "loses the selection" issue. And, it is make sense to have both component re-render, when child trigger onProjectIdChange(), parent's selectedProjectId is updated, and the value was passed to ChildComponent, so when selectedProjectId updated, ChildComponent should be re-render too, it is very normal data flow when we deal with form elements, all value should be controlled by react but not by html5 element, unless you want debounce inputNinon
It’s impossible not to rerender child with your components, since you pass an ID to your ChildComponent and it always triggers that.Sonics
W
6

Since your child component's props are changing, the child component will re-render regardless, thus the solution is prevent the child component's props from changing when the Parent Component re-render.

1st, you can remove the prop selectedProjectId from the child component. The select-option doesn't need to be updated base on state change. Then add memo to the child component.

ChildComponent

function ChildComponent({ onProjectIdChange }) { 
  .....
  return (
    .....
    <select onChange={handleProjectChange}>

....
export default React.memo(ChildComponent);

2nd, in the ParentComponent use useCallback to prevent handleProjectIdChange from changing on every re-render.

ParentComponent

....
const handleProjectIdChange = useCallback(
  (projectId) => {
    setSelectedProjectId(projectId);
  },
  [setSelectedProjectId]
);
....
return (
  ....
  <ChildComponent
    onProjectIdChange={handleProjectIdChange}
  />
  ....
);
Wabble answered 20/4, 2023 at 18:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.