Technical knowledge
Technical knowledge

Reputation: 222

not able to update state in reactsJs

i am using table input field to update state under map function to render it according to number of elements in the state.But when I used value={item.account} values are not updated in the state.which works fine when I use **value={accountCounter.account} where accountCounter is reactjs hook of type

const[accountCounter,setAccountCounter]=useState([
          { id: 1, account:"" ,accountOwner:""},
          { id: 2, account: "hi",accountOwner:"" },
          { id: 3, account: "bu" ,accountOwner:""}

And here is my rendering function

 accountCounter.map((item,key)=>{
  return(
    <tr key={key}>
    <td><input  type="text" value={item.account}
    name="account" onChange={(e)=>handleAccountCounter(e,item)}/></td>
    <td><input  type="text" value={item.accountOwner}
    name="accountName" onChange={(e)=>handleAccountCounter(e,item)}/></td>
    <td><span onClick={()=>deleteAccount(item.id)}>X</span></td>
    </tr>   
     )
  })}

here is my handleAccountCounter

const  handleAccountCounter=(event,counter)=>{
 const index = accountCounter.indexOf(counter);
 accountCounter[index][event.target.name]=event.target.value;
 setAccountCounter(accountCounter)
  }

But the state is not getting modified when in input field value={item.account}.dont know why..will you help me out

Upvotes: 2

Views: 66

Answers (3)

Ali Klein
Ali Klein

Reputation: 1908

Use the previous state values to create a new array:

const App = () => {
  const [accountCounter, setAccountCounter] = useState([
    { id: 1, account: "", accountOwner: "" },
    { id: 2, account: "hi", accountOwner: "" },
    { id: 3, account: "bu", accountOwner: "" }
  ]);

  const handleAccountCounter = (event, counter) => {
    setAccountCounter((prevAccountCounter) => {
      const newCounter = [...prevAccountCounter];
      newCounter[prevAccountCounter.indexOf(counter)][event.target.name] =
        event.target.value;
      return newCounter;
    });
  };

  const deleteAccount = (id) => {
    setAccountCounter((prevAccountCount) =>
      prevAccountCount.filter((item) => item.id !== id)
    );
  };

  return accountCounter.map((item, index) => (
    <tr key={index}>
      <td>
        <input
          type="text"
          value={item.account}
          name="account"
          onChange={(e) => handleAccountCounter(e, item)}
        />
      </td>
      <td>
        <input
          type="text"
          value={item.accountOwner}
          name="accountOwner"
          onChange={(e) => handleAccountCounter(e, item)}
        />
      </td>
      <td>
        <span onClick={() => deleteAccount(item.id)}>X</span>
      </td>
    </tr>
  ));
};

Upvotes: 1

Hypocritic
Hypocritic

Reputation: 41

Using Kartikey's answer, but you should use a callback because state updates are asynchronous:

const handleAccountCounter = (event, counter) => {
  setAccountCounter((prev) => {
    let newCounter = [...prev];
    newCounter[prev.indexOf(counter)][event.target.name] = event.target.value;
    return newCounter;
  });
};

This ensures that the state updates in the correct order. See here for more info: https://dmitripavlutin.com/how-react-updates-state/

Upvotes: 1

Kartikey
Kartikey

Reputation: 5002

Instead of this

const  handleAccountCounter = (event,counter) => {
     const index = accountCounter.indexOf(counter);
     accountCounter[index][event.target.name]=event.target.value;
     setAccountCounter(accountCounter)
}

Do like this

const  handleAccountCounter = (event, counter) => {
     let temp = [...accountCounter] // Make a copy of state and then perform operations
     const index = temp.indexOf(counter);
     temp[index][event.target.name] = event.target.value;
     setAccountCounter(temp)
}

Upvotes: 1

Related Questions