Home > OS >  React SetValues When input onChange event happen reload the form after first change
React SetValues When input onChange event happen reload the form after first change

Time:11-01

Appreciate your help. I have an issue with the setValues in handleChange function, after the first onChange Event happens the form seems to reloaded and can't do more changes to the field. All I've been trying to do is to create a reusable form fields.

I have created a file BuildForm.js which has a custom hook that return the fields. `

import { useState } from 'react';

const BuildForm = () => {
  const [values, setValues] = useState({});

  const handleChange = (event) => {
      // event.persist();
      let name = event.target.name;
      let value = event.target.value;
      setValues({...values, [name]:value});  // this is line with the issue
      console.log(name, value);
  };

  const Name = (props) => {
    return(
      <div className="fullwidth">
        <p className="description"><strong>{props.label}</strong></p>
        <div className="firstname halfwidth left">
          <label htmlFor="first_name">FIRST</label>
          <input type="text" name="first_name" onChange={handleChange}/>
          { errors.first_name && <p className="validation">{errors.first_name}</p> }
        </div>
        <div className="lastname halfwidth right">
          <label htmlFor="last_name">LAST</label>
          <input type="text" name="last_name" onChange={handleChange} />
          { errors.last_name && <p className="validation">{errors.last_name}</p> }
        </div>
      </div>
    );
  };

  return {
    Name,
  }
};

export default BuildForm;

`

and in the other file FirstForm.js where my form goes, i have this code `

import './App.css';
import React, {useState} from 'react';
import { Link, Routes, Route, useNavigate } from 'react-router-dom';
import BuildForm from './Hooks/BuildForm';

function FirstForm() {
  const navigate = useNavigate();
  const MyForm = BuildForm();

  return (
    <div className="App">
      <div id="header">
        <img src={logo} className="logo" alt="logo"/>
      </div>
      <div id="pagebody">
        <div id="formcontainer">
          <form id="myForm">
            <MyForm.Name label="Client Name"/>
            <div className="submitbutton fullwidth"><input type="submit" /></div>
          </form>
        </div>
      </div>
    </div>
  );
}

export default FirstForm;

`

CodePudding user response:

You are missing the value attribute to inputs:

<input type="text" name="first_name" value={values.first_name} onChange={handleChange}/>

CodePudding user response:

Try with this:

const handleChange = (event) => {
      // event.persist();
      let name = event.target.name;
      let value = event.target.value;
      values[name] = value;
      setValues(values);
      console.log(name, value);   };

CodePudding user response:

That line is not the issue, nor do I see evidence of the hook you speak about. The issue is that you are treating a function as if it were a component.

Since values state does not affect the Name component i.e. the value is not being passed as a prop, react has no need to re-render Name component when values changes. Also since BuildForm is not being rendered, it gets no lifecycle updates, therefore its children also do not get re-rendered.

You need to rethink your design. Either move the state values into the Name component, or use an actual hook to create the state update logic.

Using a hook example

const BuildForm = () => {
  const useCreateValues = (initial) => { // <-- hook
    const [values, setValues] = useState(initial);
    const handleChange = (event) => {
      // event.persist();
      let name = event.target.name;
      let value = event.target.value;
      setValues(oldValues => ({...oldValues, [name]:value}));  // this is line with the issue
      console.log(name, value);
    };
    return [values, handleChange];
  };

  const Name = ({...props, initial = {}}) => {
    const [values, handleChange] = useCreateValues(initial);

    return(
      <div className="fullwidth">
        <p className="description"><strong>{props.label}</strong></p>
        <div className="firstname halfwidth left">
          <label htmlFor="first_name">FIRST</label>
          <input type="text" name="first_name" onChange={handleChange}/>
          { errors.first_name && <p className="validation">{errors.first_name}</p> }
        </div>
        <div className="lastname halfwidth right">
          <label htmlFor="last_name">LAST</label>
          <input type="text" name="last_name" onChange={handleChange} />
          { errors.last_name && <p className="validation">{errors.last_name}</p> }
        </div>
      </div>
    );
  };

  return {
    Name,
  }
};
  • Related