简体   繁体   中英

React Form not updating state onChange

I'm trying to practice React forms, and I can't seem to solve this error. I've developed a multi-input form and I need the value to update the parent's state. When I start typing in the input field it triggers the Switch case default. I'm not sure if maybe I'm typing the 'handleChange' function wrong or if I should have a separate state for the state.data. Any advice would be much appreciated

import React, { useState } from 'react';
import Form from './Form';
import Results from './Results';

function App() {
    const [state, setState] = useState({
        data: 1,
        Name: '',
        Email: '',
        City: ''
    });

    const nextStep = () => {
        setState({
            data: state.data + 1
        });
  };

  const handleChange = e => {
        let field = e.target.name;
        let val = e.target.value;
        setState({ [field]: val });
    };

    switch (state.data) {
        case 1:
            return (
                <div className='App-container'>
                    <Form
                        button='Next'
                        nextStep={nextStep}
                        name='Name'
                        state={state.name}
                        handleChange={handleChange}
                    />
                </div>
            );
        case 2:
            return (
                <div className='App-container'>
                    <Form
                        button='Next'
                        nextStep={nextStep}
                        name='Email'
                        state={state.email}
                        handleChange={handleChange}
                    />
                </div>
            );
        case 3:
            return (
                <div className='App-container'>
                    <Form
                        button='Submit'
                        nextStep={nextStep}
                        name='City'
                        state={state.city}
                        handleChange={handleChange}
                    />
                </div>
            );
        case 4:
            return (
                <div className='App-container'>
                    <Results data={state} />
                </div>
            );
        default:
            return 'Error';
    }
}

export default App;

import React from 'react';

const Form = ({ button, nextStep, name, state, handleChange }) => {
    const handleSubmit = e => {
        e.preventDefault();
        nextStep();
    };

    return (
        <div className='Form-container'>
            <form onSubmit={handleSubmit}>
                <input
                    type='text'
                    placeholder={name}
                    name={name}
                    value={state}
                    onChange={handleChange}
                />
                <input type='submit' value={button} />
            </form>
        </div>
    );
};

export default Form;


import React from 'react';

const Results = ({ data }) => {
    return (
        <div>
            <h1>Info</h1>
            <p>{data.name}</p>
            <p>{data.email}</p>
            <p>{data.city}</p>
        </div>
    );
};

export default Results;

You losing state on handleChange while expecting it to merge with the current one, but it is not how useState works in contradiction to this.setState in class components:

// Results new state: { data };
setState({ data: state.data + 1 });

// Instead update the copy of the state.
// Results new state: { data, Name, Email, City }
setState({ ...state, data: state.data + 1 });

Check useState note in docs :

Note

Unlike the setState method found in class components, useState does not automatically merge update objects. You can replicate this behavior by combining the function updater form with object spread syntax.

Another option is useReducer, which is more suited for managing state objects that contain multiple sub-values.

I recommend using a custom hook for form inputs.like follows

//useForm.js

const useForm = defaultValues => {
  const [values, setValues] = useState(defaultValues);
  const handleChange = ({ name, value }) => {
    setValues(prevState => ({ ...values, [name]: value }));
  };
  const reset = () => {
    setValues(null);
  };
  return [values, handleChange, reset];
};

inside component

 const [formValues, handleChange, resetForm] = useForm();

 return (
    <>
     <Input
       value={formValues.name}
        onChange: str => handleChange({ name: "name", value: str })
      />

     <Input
       value={formValues.email}
        onChange: str => handleChange({ name: "email", value: str })
      />
    </>
  )

You need to spared old state

  const handleChange = e => {
        let field = e.target.name;
        let val = e.target.value;
        setState({ ...state, [field]: val });
    };

this is setState({ ...state, [field]: val });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM