Declaring a function component within another function component leads to all
sorts of trouble. don’t do it. A few examples of the symptoms your component may
be having are:
import { useState } from "react";
export default function App() {
const [state, setState] = useState("");
const Input = () => (
<input value={state} onChange={(e) => setState(e.target.value)} />
);
return (
<div>
<Input />
</div>
);
}
import { useState } from "react";
export default function App() {
const [buttonState, buttonStateSet] = useState(0);
const Component = () => {
const [state, setState] = useState("");
return <input value={state} onChange={(e) => setState(e.target.value)} />;
};
return (
<div>
{buttonState}
<Component />
<button onClick={() => buttonStateSet(buttonState + 1)}>
State gets deleted
</button>
</div>
);
}
This has to do with the way react renders. Every time you change the state in a
component, the component declaring the state will rerun their own function.
Then, for all the returned component instances, it will compare their identity
during the current render loop to the one of the the previous render loop. If
they are different, the previous one will get dismounted; and the current one
mounted.
If you declare functions within functions, the reference of the child functions
will never remain stable across different runs of the parent function. This is
because running the function will re-declare all variables that are declared
within that function. Thus, they will have entirely new places in memory. In
terms of code, this may look like this:
function parent() {
return function child() {};
}
parent() === parent();
Extract the component to the top level scope. This way the reference of the
component will stay the same throughout its lifetime.
import { useState } from "react";
const Input = ({ state, setState }) => (
<input value={state} onChange={(e) => setState(e.target.value)} />
);
export default function App() {
const [state, setState] = useState("");
return (
<div>
<Input state={state} setState={setState} />
</div>
);
}
import { useState } from "react";
const Component = () => {
const [state, setState] = useState("");
return <input value={state} onChange={(e) => setState(e.target.value)} />;
};
export default function App() {
const [buttonState, buttonStateSet] = useState(0);
return (
<div>
{buttonState}
<Component />
<button onClick={() => buttonStateSet(buttonState + 1)}>
State gets deleted
</button>
</div>
);
}