badAtHooks
badAtHooks

Reputation: 149

MaterialUI Text Field input getting 'undefined' values with React Hooks

I am using React Hooks - useState and useEffect - to grab email/password form input from text fields provided by Material UI (specifically using the BootstrapInput under "Customized Inputs" on that page).

I have looked at similar StackOverflow questions about getting form values with React Hooks. Unfortunately, these solutions do not work for me as I believe my problem is with the Material UI Text Field I am using. In the other questions' solutions, the code uses a simple unstyled input tag.

I've tried putting the handleChange function in InputField.js - in this case, values.email and values.password are updated and printed correctly. However, validation (with the validate function) must be kept within Form.js. handleChange uses useState (setValues) to set the values variable, and validate uses values. Therefore handleChange must be kept in Form.js which is where I am having my problem.

Working demo here: https://glitch.com/~blue-peridot (click Show on the top-left corner, next to the project name and open your actual browser console to see output... ignore warnings from browser)

Firstly:

From Form.js - I expect values.email and values.password (lines 29-30) to be printed to console as they are entered in the InputField.

Actual output - undefined

Secondly:

isSubmitting is one step behind. I expect the value of isSubmitting to be set to True after clicking Login once (provided the input is valid). However, the value is not updated until after the second click.

Upvotes: 0

Views: 2667

Answers (2)

joshwilsonvu
joshwilsonvu

Reputation: 2679

A few things in Form.js:

  1. Your useEffect hook is missing dependencies on both isSubmitting and handleChange.
  2. You should be able to move validate outside of the component.
  3. Optional, but: since you're passing handleChange and handleSubmit to other components, it will boost performance to wrap them in useCallback hooks, like
const handleChange = useCallback((event) => {
 event.persist();
 setValues(values => ({ ...values, [event.target.name]: event.target.value }));
}, [values]);

const handleSubmit = useCallback((event) => {
 if (event) event.preventDefault();
 setErrors(validate(values));
 setIsSubmitting(true);
}, [values]);

If you have ESLint setup or can, eslint-plugin-react-hooks helps to catch these issues.

Upvotes: 1

Josh Wooding
Josh Wooding

Reputation: 852

You need to pass your props through on your InputField component. Currently, you only have label as a prop.

e.g.

const InputField = ({
    label,
...others
}) => {
    const classes = useStyles();
    return (
        <div className={classes.root}>
            <FormControl className={classes.margin}>
                <InputLabel className={classes.label} shrink htmlFor="bootstrap-input">
                    {label}
                </InputLabel>
                <BootstrapInput {...others} />
            </FormControl>
        </div>
    )
}

Or you can only pass specific props through.

Upvotes: 1

Related Questions