admin管理员组

文章数量:1415476

I have found that React does not update a ponent when an element in the array is changed. Instead, a new array must be cloned and put in its place.

For example, I have an array of _suggestedPeople. When the UI element representing one of these people is clicked, I'd like to register this by calling selectPerson.

I would expect React to update after doing this:

selectPerson: function(personID, selected) {
    var person = _.find(_suggestedPeople, {id: personID});
    if (person) {
      person.selected = selected; 
    }
    return person;
  },

However, I end up doing this instead, which seems unnecessary:

selectPerson: function(personID, selected) {
    var index = _.findIndex(_suggestedPeople, {id: personID});
    var found = index !== -1;
    if (found) {
      var people = _.cloneDeep(_suggestedPeople);
      people[index].selected = selected;
      _suggestedPeople = people; 
    }
    return found;
  },

Is this the latter the correct way to update the array data of a React ponent? Or am I missing something?

I have found that React does not update a ponent when an element in the array is changed. Instead, a new array must be cloned and put in its place.

For example, I have an array of _suggestedPeople. When the UI element representing one of these people is clicked, I'd like to register this by calling selectPerson.

I would expect React to update after doing this:

selectPerson: function(personID, selected) {
    var person = _.find(_suggestedPeople, {id: personID});
    if (person) {
      person.selected = selected; 
    }
    return person;
  },

However, I end up doing this instead, which seems unnecessary:

selectPerson: function(personID, selected) {
    var index = _.findIndex(_suggestedPeople, {id: personID});
    var found = index !== -1;
    if (found) {
      var people = _.cloneDeep(_suggestedPeople);
      people[index].selected = selected;
      _suggestedPeople = people; 
    }
    return found;
  },

Is this the latter the correct way to update the array data of a React ponent? Or am I missing something?

Share Improve this question asked May 11, 2015 at 21:51 Matt NorrisMatt Norris 8,85614 gold badges60 silver badges92 bronze badges 4
  • Perhaps a different approach would fit better in the immutability paradigm. E.g. storing a reference to the selected person object in another property of the ponent instead of mutating the person objects. – Fabrício Matté Commented May 11, 2015 at 21:57
  • Why not just trigger an update when a new selection occurs? React doesn't track properties of objects, so just setting selected of an object wouldn't work. For example, you could call forceUpdate. – WiredPrairie Commented May 11, 2015 at 22:12
  • Sorry I am finding it a little hard to follow your code snippets out of context, but I think you should store selected person in the ponents state (or the state of its parent depending on which ponent selectPerson is implemented in) and force a re render with a call to this.setState({_suggestedPeople: people, selectedPerson: person}). There is a fiddle jsfiddle/map5vf94/11 in the answer of this question which might be what you are trying to do- stackoverflow./questions/30042657/… – Dave Pile Commented May 12, 2015 at 1:00
  • Thank you. I did use forceUpdate at first, but felt I shouldn't have to, rather that there was an underlying problem I was circumventing. Maybe that's not the case. For this problem, I need to track multiple selections. Would you advocate a second list? selectedPeople array instead of selectedPerson object? – Matt Norris Commented May 12, 2015 at 18:50
Add a ment  | 

3 Answers 3

Reset to default 0

You don't appear to be using React's built in state management. If you do, a middle ground between your two approaches of updating the state will work. A ponent will re-render when it's state or properties change at all.

Edit: This code is outdated and not good practice. See updated jsfiddle below

Initialise the ponents state by implementing

getInitialState: function () {

   var whereverItComesFrom = [
      {id: 1, selected: false},
      {id: 2, selected: false}
   ];

   return {
       suggestedPeople: whereverItComesFrom
   }
}

your render method renders from this:

render: function () {
    var _this = this;
    var peeps = this.state.suggestedPeople.map(function(person, index){
        return <label key={index}><input type='checkbox' checked={person.selected} value={person.id} onChange={_this.handlePersonClick}/>{person.id}</label>;
    });

    return <div>{peeps}</div>;
},

handlePersonClick can be a merge of your methods:

handlePersonClick: function(e) {
    var selectedId = e.target.value;
    var checked = e.target.checked;
    var peeps = this.state.suggestedPeople;
    var index = _.findIndex(peeps, {id: selectedId});

    peeps[index].selected = checked;

    this.setState({suggestedPeople: peeps});

}

Edit: The above was very ill informed early days react for me. I've updated the fiddle link below and it should serve as a good basic example of solving this problem.

Full jsfiddle

I think you are doing it wrong. You may e to react from angular js. Intead of using a function, To manipulate objects, Use useState. Local state with in ponent.

Sample:

const Comp = () => {
  const [selectedPerson, setSelectedPerson] = useState({});
  function onSelect(personID, selected) {
    var person = _.find(_suggestedPeople, { id: personID });
    if (person) {
      person.selected = selected;
    }
    setSelectedPerson(person);
  }
  return (
    <div>
      {selectedPerson.name}
      <select>
        <option onSelect={() => onSelect(id, "ssjsjs")}></option>
      </select>
    </div>
  );
};

React setState is a shallow parison, there is no need to use cloneDeep. react can be triggered to re-render only by changing the pointer to the address of _suggestedPeople. you can try like this:

const App = () => {
  const [_suggestedPeople, setSuggestedPeople] = useState([
    {
      id: '1',
      name: 'A',
      selected: false,
    },
    {
      id: '2',
      name: 'B',
      selected: false,
    },
  ])
  const handleUserClick = (personID, selected) => {
    const person = _.find(_suggestedPeople, { id: personID })
    if (person) {
      person.selected = selected
    }
    setSuggestedPeople([..._suggestedPeople])
  }

  return (
    <div>
      {_suggestedPeople.map((user) => {
        return (
          <div
            onClick={() => {
              // selected or other things
              handleUserClick(user.id, true)
            }}
            className={user.selected ? 'selected' : ''}
          >
            {user.name}
          </div>
        )
      })}
    </div>
  )
}

export default App

本文标签: javascriptHow do I update an array for a React componentStack Overflow