Skip to content

Sibling Components With Internal States are Re-Rendering Each Other #12918

@churbis

Description

@churbis

I'm using React Router as a...

framework

Reproduction

  1. Create a route with components that have inputs with internal managed state (Playground.tsx below)
  2. Run in dev and load the route
  3. Edit the text in the non-managed (DOM value) input-- notice that all of the other sibling managed state components don't re-render
  4. Edit the text one of the the input components with internal managed state
  5. Observe that all of the sibling input components re-render using react dev tools

InputComponentRoute.tsx

import { useEffect, useRef, useState } from "react";
import ComponentInSeparateFile from "./TestExternalComponent";

export default function Playground() {
    return <div>
        <div>
            <input type="text" className="text-sm border border-gray-300 rounded-md p-2 cursor-text" placeholder="input text" />
        </div>
        <div>
            <InputWithState name="input 1" />
        </div>
        <div>
            <InputWithState name="input 2" />
        </div>
        <div>
            <MultiInputParentWithState />
        </div>
        <div>
            <ComponentInSeparateFile />
        </div>
    </div>;
}

function InputWithState(props: {name: string}) {
    const [value, setValue] = useState('');
    return <>
        <label htmlFor={props.name}>{props.name}</label>
        <input type="text" className="text-sm border border-gray-300 rounded-md p-2 cursor-text" placeholder="input text" value={value} onChange={(e) => setValue(e.target.value)} />
    </>;
}

function MultiInputParentWithState() {
    const [input1, setInput1] = useState('');
    const [input2, setInput2] = useState('');
    return <div>
        <input type="text" className="text-sm border border-gray-300 rounded-md p-2 cursor-text" placeholder="input text" value={input1} onChange={(e) => setInput1(e.target.value)} />
        <input type="text" className="text-sm border border-gray-300 rounded-md p-2 cursor-text" placeholder="input text" value={input2} onChange={(e) => setInput2(e.target.value)} />
    </div>;


}

TextExtnernalComponent.tsx

import { useState } from "react";

export default function ComponentInSeparateFile() {
    const [value, setValue] = useState('');
    return <div>
        <h1>Test External Component</h1>
        <input type="text" className="text-sm border border-gray-300 rounded-md p-2 cursor-text" placeholder="input text" value={value} onChange={(e) => setValue(e.target.value)} />
    </div>;
}

System Info

System:
    OS: Linux 5.15 Ubuntu 24.04.1 LTS 24.04.1 LTS (Noble Numbat)
    CPU: (12) x64 Intel(R) Core(TM) i7-8700K CPU @ 3.70GHz
    Memory: 6.33 GB / 15.59 GB
    Container: Yes
    Shell: 5.2.21 - /bin/bash
  Binaries:
    Node: 23.6.0 - ~/.nvm/versions/node/v23.6.0/bin/node
    npm: 10.9.2 - ~/.nvm/versions/node/v23.6.0/bin/npm

(this is WSL, I'm using Chrome latest on windows 10 to visit the page)

Used Package Manager

npm

Expected Behavior

Sibling components managing their own input state should not trigger re-renders on other component ancestor trees when the parent is not re-rendering. This makes it hard to debug your code.

Actual Behavior

Sibling components trigger re-renders on other components in the parent component.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions