I have been building Login page and facing this problem.
I have multiple component like <Section/>, <Container/>, <FormLayout/>, <InputText/>
.
Login page
export default function Login() {
const [mail,setMail] = useState('');
const handleMailChange = (e) => {
setMail(e.target.value);
};
return (
<Section className="someClassName">
<Container size="l" wrapper={true}>
<section className="someClassName">
<Container size="s" className="someClassName">
<FormLayout arg1="" arg2="">
<InputText
type="email"
value={mail}
onChange={handleMailChange}
/>
</FormLayout>
</Container>
</section>
</Container>
</Section>
);
}
Components are defined like this in other files
const Section = ({ className = "", children }) => {
return <div>{children}</div>;
};
const Container = ({ size='', wrapper={false}, children }) => {
return <div>{children}</div>;
};
const InputText = ({ value = "", type = "text", onChange = "" }) => {
const [text, setText] = useState(value);
const handleChange = useCallback(
(event) => {
setText(event.target.value);
if (typeof onChange === "function") {
onChange(event);
}
},
[onChange]
);
return <input value={text} type={type} onChange={handleChange} />;
};
I found that every time I type any character Section
re-renders and input box is out of the focus. How can i fix this problem ?
Edit: I was able to generate this problem here.
4
Answers
It looks like you’re trying to make
InputText
controlled and both uncontrolled at the same time, this may be what is causing your issue.There is no need to keep a state value of input as it is now, rather just make it this:
Notice that I’m not defaulting these values, so if you still want to give it uncontrolled functionality it will work.
If there’s another reason you need to keep local state of that input control, then you need to provide that context in the question.
It is re-rendering because the input field is dependent on mail state. And whenever value change, the state update so it re-render.
And if you want to avoid this behavior use useRef hook.
Its general practice to use useRef hook with form fields (input, select etc) so that you don’t need to keep updating the value of Field.
Here is the updated code for the InputText:-
The problem is that you declare nested components like:
This is a bad practice. Every time the
Section
component is rendered a newElement
component is created and React can’t keep track of the tree.The easiest fix is to change the nested component to functions e.g.
<Element />
toElement()
Sections component:
You have to do the same with
Container
Here is the working code:
You can also move the nested components outside of the parent component
Extending on @Konrad’s answer.
This is the problem component and you have the same problem in the
Container
component which is a little more complex.The problem is that these
Element
components are recreated every time a re-render occurs and that will take away focus from the children. It seems that in both of your cases the only difference is the class names, so instead of creating a full new component to render based off prop changes, rather just store the effective changed prop values that you’re passing down.Like this:
Don’t forget to do the same thing to your
Container
component.