Xavier Munroe
Xavier Munroe

Reputation: 41

Resetting initial state of useState

In order to improve my React skills, I have been trying to build a reusable form state hook and form validator. My custom hook, FormState, initializes an object with empty strings for values to be used as an initial state for my hook. I wrote a function, clearInputs, that I expected to reset my inputs to their initial state but it is failing to update.

I've poked around looking for an answer, even referring to this Stack Overflow post: Reset to Initial State with React Hooks . Still no dice.

// MY FORMSTATE HOOK
import { useState } from 'react';

const FormState = props => {
    let initialState = { ...props };

    const [ inputs, setInputs ] = useState(initialState);

    const [ errors, setErrors ] = useState(initialState);

    const handleInput = e =>
        setInputs({
            ...inputs,
            [e.target.name]: e.target.value
        });

    const handleError = errs => setErrors({ ...errors, ...errs });

    const resetForm = () => {
        setInputs({ ...initialState });
        setErrors({ ...initialState });
    };

    const clearInputs = () => {
        console.log('SUPPOSED TO CLEAR', initialState)
        console.log('MY INPUTS', inputs)

        setInputs({ ...initialState });

        console.log('AFTER THE SETTING', inputs)
    };

    return [ inputs, handleInput, errors, handleError, resetForm, clearInputs ];
};

export default FormState;
// REGISTER FORM
import React, { useEffect } from 'react';
import { connect } from 'react-redux';

import FormState from './formState';
import Field from './field';

import { registerUser } from '../../actions/users';

import './forms.css';

const RegisterForm = props => {
    const isLoggedIn = localStorage.getItem('user');

    useEffect(
        () => {
            if (isLoggedIn) {
                const parsedUser = JSON.parse(isLoggedIn);
                props.history.push(`/profile/${parsedUser.pk}`);
            }
        },
        [ isLoggedIn ]
    );

    const initialInputs = {
        username: '',
        password1: '',
        password2: '',
        first_name: '',
        last_name: ''
    };

    const [ inputs, handleInput, errors, handleErrors, resetForm, clearInputs ] = FormState(initialInputs);

    const handleSubmit = e => {
        e.preventDefault();

        const validForm = validate(inputs, handleErrors);

        if (validForm) {
            props.registerUser(inputs);
            resetForm();
        }
        else {
            clearInputs();
        }
    };

    return (
        <div className='form-wrap'>
            <h1>Register Here</h1>
            <form className='form' onSubmit={handleSubmit}>
                <Field
                    label='Username'
                    fieldname='username'
                    value={inputs.username}
                    placeholder='Enter Your Username'
                    fielderror={errors.username}
                    handleInput={handleInput}
                    classNames='form-section'
                />
                <Field
                    label='Password'
                    fieldname='password1'
                    value={inputs.password1}
                    placeholder='Enter Your Password'
                    fielderror={errors.password1}
                    handleInput={handleInput}
                    classNames='form-section'
                />
                <Field
                    label='Confirm Password'
                    fieldname='password2'
                    value={inputs.password2}
                    placeholder='Confirm Your Password'
                    fielderror={errors.password2}
                    handleInput={handleInput}
                    classNames='form-section'
                />
                <Field
                    label='First Name'
                    fieldname='first_name'
                    value={inputs.first_name}
                    placeholder='Enter Your First Name'
                    fielderror={errors.first_name}
                    handleInput={handleInput}
                    classNames='form-section'
                />
                <Field
                    label='Last Name'
                    fieldname='last_name'
                    value={inputs.last_name}
                    placeholder='Enter Your Last Name'
                    fielderror={errors.last_name}
                    handleInput={handleInput}
                    classNames='form-section'
                />
                <button type='submit' className='submit-button'>
                    Submit
                </button>
            </form>
        </div>
    );
};

const validate = (inputs, handleErrors) => {
    let errs = {};
    const { username, password1, password2, first_name, last_name } = inputs;
    if (!username) {
        errs.username = 'Username is missing';
    }
    if (!password1) {
        errs.password1 = 'Password is missing';
    }
    if (!password2) {
        errs.password2 = 'Confirm password is missing';
    }
    if (!first_name) {
        errs.first_name = 'First name is required';
    }
    if (!last_name) {
        errs.last_name = 'Last name is required';
    }
    if (username.length < 6) {
        errs.username = 'Username is too short';
    }
    if (password1.length < 8) {
        errs.password1 = 'Password is too short';
    }
    if (password1 !== password2) {
        errs.password1 = 'Passwords must match';
        errs.password2 = 'Passwords must match';
    }

    if (Object.keys(errs).length) {
        handleErrors(errs);
        return false;
    }
    else {
        return true;
    }
};

const mapStateToProps = state => {
    return {
        loggedInUser: state.users.loggedInUser,
        registerPending: state.users.registerPending,
        registerError: state.users.registerError
    };
};

const mapDispatchToProps = dispatch => {
    return {
        registerUser: newUser => {
            dispatch(registerUser(newUser));
        }
    };
};

export default connect(mapStateToProps, mapDispatchToProps)(RegisterForm);

When clearInputs is triggered, it should reset inputs to the initial state. Instead nothing is happening. Any help is really appreciated.

EDIT: Let me further clarify. Each Field in my form is passed a value from inputs (username, password1, etc). When clearInputs is called, it clears the inputs in the hook but it DOES NOT clear the values in the Field.

Upvotes: 4

Views: 12136

Answers (2)

Bear-Foot
Bear-Foot

Reputation: 774

About why you log isn't right, one must understand this: Everytime your hook is called (basically on every form render) there is a new clearInputs function created, that has its own version of inputs. So, within the clearInputs function itself, inputs cannot change, because they come from higher up in the scope, the useState.

If you want to notice changes between 2 calls of your hook, you could log inputs just before returning [inputs, ...].

Again, in your hook, you are not calling setInputs, you are defining a clearInputs function that will trigger a state change, that will re-render your component, which will use your hook once again, your hook will read the new value of inputs, and create a new clearInputs function.

Upvotes: 0

lecstor
lecstor

Reputation: 5707

Your clearInputs function is working as intended. The setInputs function returned by useState is asynchronous, causing your 'AFTER THE SETTING' console log to show the value of inputs before it has been updated.

Basic use of your custom hook is shown to work here.. https://codesandbox.io/s/jznpk7w85w

btw, you should prefix your custom hook name with use.. https://reactjs.org/docs/hooks-custom.html#extracting-a-custom-hook

Upvotes: 1

Related Questions