I want to change the content of a child component in response to a user event in another child component without causing the parent to re-render.
I've tried storing the child state setter to a variable in the parent but it is not defined by the time the children have all rendered, so it doesn't work.
Is there a minimal way to accomplish this (without installing a state management library)?
ChildToChild.tsx
import React, {
Dispatch,
SetStateAction,
useEffect,
useRef,
useState,
} from "react";
export default function ChildToChild() {
const renderCounter = useRef(0);
renderCounter.current = renderCounter.current + 1;
let setChildOneContent;
const childOneContentController = (
setter: Dispatch<SetStateAction<string>>
) => {
setChildOneContent = setter;
};
return (
<div>
<h1>Don't re-render me please</h1>
<p>No. Renders: {renderCounter.current}</p>
<ChildOne childOneContentController={childOneContentController} />
<ChildTwo setChildOneContent={setChildOneContent} />
</div>
);
}
function ChildOne({
childOneContentController,
}: {
childOneContentController: (setter: Dispatch<SetStateAction<string>>) => void;
}) {
const [content, setContent] = useState("original content");
useEffect(() => {
childOneContentController(setContent);
}, [childOneContentController, setContent]);
return (
<div>
<h2>Child One</h2>
<p>{content}</p>
</div>
);
}
function ChildTwo({
setChildOneContent,
}: {
setChildOneContent: Dispatch<SetStateAction<string>> | undefined;
}) {
return (
<div>
<h2>Child Two</h2>
<button
onClick={() => {
if (setChildOneContent) setChildOneContent("content changed");
}}
>
Change Child One Content
</button>
</div>
);
}