2

I'm trying to set up so that when I type a name in the input of the Person component the state in the App component is updated and in turn updates the value of a prop in Person, however it appears the state change is happening, but the prop isn't updated, can anyone help me figure out what is wrong?

App

const App = () => {
  const [persons, setPersons] = useState([
    {id: "key1", name: "Daniel", age: "28"},
    {id: "key2", name: "John", age: "30"},
    {id: "key3", name: "Doe", age: "60"}
  ]);

  const nameChangedHandler = (id, event) => {
    console.log(event.target.value);
    console.log(id);
    const personIndex = persons.findIndex(p => {
      return p.id === id;
    });

    const person = {
      ...persons[personIndex]
    };

    person.name = event.target.value;

    const pers = [...persons];
    persons[personIndex] = person;

    setPersons(pers);
    console.log(persons);
  };

  let people = persons.map((person, index) => {
    return (
      <Person
        name={person.name}
        key={person.id}
        age={person.age}
        changed={nameChangedHandler.bind(this, person.id)}
      />
    );
  });

  return <div className="App">{people}</div>;
};

Person

const person = props => (
  <div className={style.Person}>
    <p onClick={props.click}>
      I'm {props.name}, and I am {props.age}!
    </p>
    <input type="text" onChange={props.changed} value={props.name} />
  </div>
);
Daniel Campos
  • 328
  • 2
  • 16
  • Possible duplicate of [Whats the best way to update an object in an array in ReactJS?](https://stackoverflow.com/questions/28121272/whats-the-best-way-to-update-an-object-in-an-array-in-reactjs) – Emile Bergeron Sep 19 '19 at 18:50

2 Answers2

5

You are assigning to the wrong variable, try the following:

const pers = [...persons];
pers[personIndex] = person;

And it should work as expected. Since you were updating your state object persons instead of the object you cloned pers, which you used to set the state, your console log was showing the expected output but your state wasn't being updated properly.

Check this working stackblitz

etarhan
  • 4,138
  • 2
  • 15
  • 29
  • 1
    FWIW, the OP can also get rid of the `bind` by using `onChange={e => changed(id, e)}` in `Person` (where `changed `is the destructured prop). E.g., and then just use `changed={nameChangedHandler}`. But to do that, they have to pass `id` to `Person` (rather than just using `id` as `key`). – T.J. Crowder Sep 19 '19 at 18:07
3

To be honest, I would use a simple map function to change the name of the particular person.

Inside nameChangedHandler function:

const updatedPersons = persons
   .map((person) => person.id === id ? {...person, name: event.target.value} : person);

and then update the local state

setPersons(updatedPersons);

It should work as expected.

Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
Szymon Pancerz
  • 237
  • 1
  • 3