I'm working in React with redux-form library. I would like to create simple form with 2 fields in functional component. After typing just 1 character in one of them I lose focus. I have created function renderInput which return Material UI TextField inputs. With native HTML input I can observe the same error. I tried to move renderInput to component inside but it haven't helped me.
Below I show my functional component implementation:
import React from "react";
import {Field, InjectedFormProps, reduxForm} from "redux-form";
import IStream from "./types/Istream";
import {CommonFieldProps, GenericField, WrappedFieldProps} from "redux-form/lib/Field";
import {TextField} from "@material-ui/core";
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: {
'& .MuiTextField-root': {
margin: theme.spacing(1),
width: '25ch',
},
},
}),
);
export const streamMethods = () => {
const renderInput = (formProps: WrappedFieldProps): JSX.Element => {
return (
<TextField
required
id="outlined-required"
value={formProps.input.value}
onChange={formProps.input.onChange}
/>
);
}
return {
renderInput,
}
}
const StreamCreate = (props: InjectedFormProps<IStream>) => {
const classes = useStyles();
return (
(
<form className={classes.root}>
<Field name="title" component={streamMethods().renderInput}/>
<Field name="description" component={streamMethods().renderInput}/>
</form>
)
)
}
export default reduxForm<IStream, {}>({
form: "streamCreate" // name of using form
})(StreamCreate);
In general, if you lose focus in a field, it means the component gets remounted. Components get remounted (among other things) when their key
changes or when their identity (the actual function/class for the component) changes.
You're returning a component function with a new identity for each render from streamMethods()
(in fact, twice per render).
I tried to move
renderInput
to component inside but it haven't helped me.
That has the same issue; the renderInput
identity also changes per render if it's an inner function. (If you really need to declare a component within another (functional) component, you could use the React.useMemo()
hook to have it retain its identity.)
Change things up to
const StreamInput = (formProps: WrappedFieldProps): JSX.Element => {
return (
<TextField
required
id="outlined-required"
value={formProps.input.value}
onChange={formProps.input.onChange}
/>
);
};
const StreamCreate = (props: InjectedFormProps<IStream>) => {
const classes = useStyles();
return (
<form className={classes.root}>
<Field name="title" component={StreamInput} />
<Field name="description" component={StreamInput} />
</form>
);
};
and you should be golden.