javascript - Modificarea corectă a array-urilor de stare în React.js


Vreau să adaug un element la sfârșitul unui array state, este acesta modul corect de a face asta?

this.state.arrayvar.push(newelement);
this.setState({ arrayvar:this.state.arrayvar });

Sunt îngrijorat că modificarea array-ului în loc cu push ar putea cauza probleme - este sigur?

Alternativa de a face o copie a matricei și de a folosi setState pare risipitoare.

Răspuns #1

Documentația React spune:

Tratează this.state ca și cum ar fi imuabil.

push-ul tău va modifica starea direct și asta ar putea duce potențial la cod predispus la erori, chiar dacă „resetezi” din nou starea după aceea. De exemplu, ar putea duce la situații în care unele metode de ciclul de viață, cum ar fi componentDidUpdate, să nu se declanșeze.

Abordarea recomandată în versiunile mai recente de React este să folosești o funcție updater atunci când modifici stările pentru a preveni condițiile de concurență:

this.setState(prevState => ({
  arrayvar: [...prevState.arrayvar, newelement]
}))

„Risipa” de memorie nu este o problemă comparativ cu erorile pe care le-ai putea întâmpina folosind modificări de stare non-standard.

Sintaxă alternativă pentru versiunile mai vechi de React

Poți folosi concat pentru a obține o sintaxă curată deoarece returnează un nou array:

this.setState({ 
  arrayvar: this.state.arrayvar.concat([newelement])
})

În ES6 poți folosi Operatorul Spread:

this.setState({
  arrayvar: [...this.state.arrayvar, newelement]
})

Răspunsul #2

Cel mai ușor, dacă folosești ES6.

initialArray = [1, 2, 3];

newArray = [...initialArray, 4]; // --> [1,2,3,4]

Noul tablou va fi [1,2,3,4]

să-ți actualizezi starea în React

this.setState({
  arrayvar: [...this.state.arrayvar, newelement]
});

Află mai multe despre destructurarea vectorilor

Răspunsul #3

Cea mai simplă metodă cu ES6:

this.setState(prevState => ({
    array: [...prevState.array, newElement]
}))

Răspunsul #4

În prezent, atât de multe persoane se confruntă cu problema actualizării stării hook-ului useState. Eu folosesc această abordare pentru a o actualiza în siguranță și am vrut să o împărtășesc aici.

Aceasta este starea mea

const [state, setState] = useState([])

Să presupunem că am un obiect numit obj1 și vreau să-l adaug în starea mea. Aș sugera să faci asta astfel

setState(prevState => ([...prevState, obj1]))

Acest lucru va insera obiectul în siguranță la sfârșit și va menține, de asemenea, consistența stării

Răspunsul #5

React poate grupa actualizările, și prin urmare abordarea corectă este să oferiți setState o funcție care efectuează actualizarea.

Pentru addon-ul de actualizare React, următoarele vor funcționa fiabil:

this.setState(state => update(state, {array: {$push: [4]}}));

sau pentru concat():

this.setState(state => ({
    array: state.array.concat([4])
}));

Următoarele arată ce face https://jsbin.com/mofekakuqi/7/edit?js,output ca exemplu a ceea ce se întâmplă dacă greșești.

Invocarea setTimeout() adaugă corect trei elemente deoarece React nu va grupa actualizările într-un callback setTimeout (vezi https://groups.google.com/d/msg/reactjs/G6pljvpTGX0/0ihYw2zK9dEJ).

Codul onClick defect va adăuga doar „Third”, dar cel reparat va adăuga F, S și T așa cum era de așteptat.

class List extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      array: []
    }
    setTimeout(this.addSome, 500);
  }

  addSome = () => {
    this.setState(
      update(this.state, {array: {$push: ["First"]}}));
    this.setState(
      update(this.state, {array: {$push: ["Second"]}}));
    this.setState(
      update(this.state, {array: {$push: ["Third"]}}));
  };

  addSomeFixed = () => {
    this.setState( state => 
      update(state, {array: {$push: ["F"]}}));
    this.setState( state => 
      update(state, {array: {$push: ["S"]}}));
    this.setState( state => 
      update(state, {array: {$push: ["T"]}}));
  };

  render() {
    const list = this.state.array.map((item, i) => {
      return <li key={i}>{item}</li>
    });
    console.log(this.state);

    return (
      <div className='list'>
        <button onClick={this.addSome}>add three</button>
        <button onClick={this.addSomeFixed}>add three (fixed)</button>
        <ul>
        {list}
        </ul>
      </div>
    );
  }
};

ReactDOM.render(<List />, document.getElementById('app'));

Răspunsul #6

Dacă folosești componente funcționale în React

const [cars, setCars] = useState([{
  name: 'Audi',
  type: 'sedan'
}, {
  name: 'BMW',
  type: 'sedan'
}])

...

const newCar = {
  name: 'Benz',
  type: 'sedan'
}

const updatedCarsArray = [...cars, newCar];

setCars(updatedCarsArray);

Răspunsul #7

Așa cum a menționat @nilgun în comentariu, poți folosi ajutoarele de imuabilitate din React. Am descoperit că acestea sunt extrem de utile.

Din documentație:

Apăsare simplă

var initialArray = [1, 2, 3];
var newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4]

initialArray este încă [1, 2, 3].