C Sharper
C Sharper

Reputation: 8626

React Js : How to use UseState In CallBack?

I have below code :

import React,{useState} from 'react'

function ReactForm() {
    const iState =[{
        Name : '',
        Email :'',
        Salary :0
    
    }]
const [state, setstate] = useState(iState);
    function validationHandler()
    {
        console.log(state);
    }

    return (
        <div>
            Name : <input type="text" onChange={(e)=>{setstate(...state, state.Name=e.target.value)}}></input>
            <br></br>            
            Email : <input type="text" onChange={(e)=>{setstate(...state, state.Email=e.target.value)}}></input>
            <br></br>            
            Salary : <input type="text" onChange={(e)=>{setstate(...state, state.Salary=e.target.value)}}></input>
            <br></br>
            <button onClick={validationHandler}>Validate Us</button>
        </div>
    )
}

export default ReactForm

I am performing basic validations here. I am receiving error : TypeError: state is not iterable

After going through few links on stackoverflow , I added - [ ] over state , but it did not helped.

EDIT 1 :

After Adding :- setstate({...state, state.Name: e.target.value}) : Unexpected token, expected "," (18:79)

enter image description here

Upvotes: 0

Views: 413

Answers (3)

Ibrahim AlRayyan
Ibrahim AlRayyan

Reputation: 31

You can do the following assignment state.Name=e.target.value ****:

You are using an array not an object, so there is nothing you can access using state.Name=e.target.value

So if wanna access it directly the same way you used you have to use state property as OBJECT not as ARRAY:

const iState = {
  Name: '',
  Email: '',
  Salary: 0

}

And the standard for the component that has form to handle is to use stateful component

OR

You can use stateless (functional) component and make form each form field its own state:

const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [salary, setSalary] = useState(0);

So the component will be:

import React, { useState } from 'react'

function ReactForm() {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');
  const [salary, setSalary] = useState(0)

  function validationHandler() {
    console.log('Name: ' + name);
    console.log('Email: ' + email);
    console.log('Salary: ' + salary);
  }

  return (
    <div>
      Name : <input
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}></input>

      <br></br>

      Email : <input
        type="text"
        value={email}
        onChange={(e) => setEmail(e.target.value)}></input>

      <br></br>

      Salary : <input
        type="text"
        value={salary}
        onChange={(e) => setSalary(e.target.value)}></input>

      <br></br>

      <button onClick={validationHandler}>Validate Us</button>
    </div>
  )
}

export default ReactForm;

Upvotes: 1

Shyam
Shyam

Reputation: 5497

Instead of having the setState called for each of the inputs you can make use of the name attribute and can refactor the code as below

import React, {useState} from 'react';

function ReactForm() {
  const [state, setstate] = useState({
    Name: '',
    Email: '',
    Salary: 0,
  });

  const handleChange = (e) => {
    const {name, value} = e.target;
    setstate((prevState) => ({...prevState, [name]: value}));
  };

  function validationHandler() {
    console.log(state);
  }

  return (
    <div>
      Name :{' '}
      <input
        type="text"
        value={state.Name}
        name="Name"
        onChange={handleChange}
      />
      <br></br>
      Email :{' '}
      <input
        type="text"
        value={state.Email}
        name="Email"
        onChange={handleChange}
      />
      <br></br>
      Salary :{' '}
      <input
        type="text"
        value={state.Salary}
        name="Salary"
        onChange={handleChange}
      />
      <br></br>
      <button onClick={validationHandler}>Validate Us</button>
    </div>
  );
}

export default ReactForm;

Refer:

Controlled Component

Upvotes: 2

Matthew Kwong
Matthew Kwong

Reputation: 2937

Your initial state is an array of objects. I'm not sure whether this is what you are looking for.

Assume your iState is (Just an object)

const iState = {
  Name: '',
  Email: '',
  Salary: 0
}

Then you should do something like this in your onChange listener

// setState should use camel case for best pratice BTW
const handleChangeName = e => setstate({
  ...state, 
  Name: e.target.value
});

If you are sticking to the array state, the listener should look something like this instead.

const handleChangeName = e => setstate([
  ...state,
  {
    ...state[0], // or whatever index you may use in the future
    Name: e.target.value
  }
]);

Upvotes: 2

Related Questions