React: come aggiornare state.item [1] nello stato usando setState?


259

Sto creando un'app in cui l'utente può progettare il proprio modulo. Ad esempio, specificare il nome del campo e i dettagli di quali altre colonne dovrebbero essere incluse.

Il componente è disponibile come JSFiddle qui .

Il mio stato iniziale è simile al seguente:

var DynamicForm = React.createClass({
  getInitialState: function() {
   var items = {};
   items[1] = { name: 'field 1', populate_at: 'web_start',
                same_as: 'customer_name',
                autocomplete_from: 'customer_name', title: '' };
   items[2] = { name: 'field 2', populate_at: 'web_end',
                same_as: 'user_name', 
                    autocomplete_from: 'user_name', title: '' };

     return { items };
   },

  render: function() {
     var _this = this;
     return (
       <div>
         { Object.keys(this.state.items).map(function (key) {
           var item = _this.state.items[key];
           return (
             <div>
               <PopulateAtCheckboxes this={this}
                 checked={item.populate_at} id={key} 
                   populate_at={data.populate_at} />
            </div>
            );
        }, this)}
        <button onClick={this.newFieldEntry}>Create a new field</button>
        <button onClick={this.saveAndContinue}>Save and Continue</button>
      </div>
    );
  }

Voglio aggiornare lo stato quando l'utente modifica uno dei valori, ma ho difficoltà a scegliere l'oggetto corretto:

var PopulateAtCheckboxes = React.createClass({
  handleChange: function (e) {
     item = this.state.items[1];
     item.name = 'newName';
     items[1] = item;
     this.setState({items: items});
  },
  render: function() {
    var populateAtCheckbox = this.props.populate_at.map(function(value) {
      return (
        <label for={value}>
          <input type="radio" name={'populate_at'+this.props.id} value={value}
            onChange={this.handleChange} checked={this.props.checked == value}
            ref="populate-at"/>
          {value}
        </label>
      );
    }, this);
    return (
      <div className="populate-at-checkboxes">
        {populateAtCheckbox}
      </div>
    );
  }
});

Come devo creare this.setStateper farlo aggiornare items[1].name?



1
qual è la risposta selezionata per questa domanda?
Braian Mellor,

Risposte:


126

È possibile utilizzare l' updatehelper dell'immutabilità per questo :

this.setState({
  items: update(this.state.items, {1: {name: {$set: 'updated field name'}}})
})

Oppure, se non ti interessa essere in grado di rilevare le modifiche a questo elemento in un shouldComponentUpdate()metodo del ciclo di vita ===, puoi modificare direttamente lo stato e forzare il rendering del componente: questo è effettivamente lo stesso della risposta di @limelights, in quanto è estrarre un oggetto dallo stato e modificarlo.

this.state.items[1].name = 'updated field name'
this.forceUpdate()

Aggiunta post modifica:

Dai un'occhiata alla lezione sulla Comunicazione semplice dei componenti dall'allenamento con reagenti per un esempio di come passare una funzione di richiamata da un genitore che detiene lo stato a un componente figlio che deve attivare un cambio di stato.


125

Dato che c'è molta disinformazione in questo thread, ecco come puoi farlo senza librerie di supporto:

handleChange: function (e) {
    // 1. Make a shallow copy of the items
    let items = [...this.state.items];
    // 2. Make a shallow copy of the item you want to mutate
    let item = {...items[1]};
    // 3. Replace the property you're intested in
    item.name = 'newName';
    // 4. Put it back into our array. N.B. we *are* mutating the array here, but that's why we made a copy first
    items[1] = item;
    // 5. Set the state to our new copy
    this.setState({items});
},

Puoi combinare i passaggi 2 e 3 se vuoi:

let item = {
    ...items[1],
    name: 'newName'
}

Oppure puoi fare tutto in una riga:

this.setState(({items}) => ({
    items: [
        ...items.slice(0,1),
        {
            ...items[1],
            name: 'newName',
        },
        ...items.slice(2)
    ]
}));

Nota: ho creato itemsun array. OP ha usato un oggetto. Tuttavia, i concetti sono gli stessi.


Puoi vedere cosa sta succedendo nel tuo terminale / console:

 node
> items = [{name:'foo'},{name:'bar'},{name:'baz'}]
[ { name: 'foo' }, { name: 'bar' }, { name: 'baz' } ]
> clone = [...items]
[ { name: 'foo' }, { name: 'bar' }, { name: 'baz' } ]
> item1 = {...clone[1]}
{ name: 'bar' }
> item1.name = 'bacon'
'bacon'
> clone[1] = item1
{ name: 'bacon' }
> clone
[ { name: 'foo' }, { name: 'bacon' }, { name: 'baz' } ]
> items
[ { name: 'foo' }, { name: 'bar' }, { name: 'baz' } ] // good! we didn't mutate `items`
> items === clone
false // these are different objects
> items[0] === clone[0]
true // we don't need to clone items 0 and 2 because we're not mutating them (efficiency gains!)
> items[1] === clone[1]
false // this guy we copied

4
@TranslucentCloud Oh sì, i metodi di supporto sono decisamente carini, ma penso che tutti dovrebbero sapere cosa sta succedendo sotto il cofano :-)
mpen

Perché abbiamo bisogno dei passaggi 2 e 3? Perché non possiamo mutare direttamente il clone dopo il primo passo?
Evmorov,

1
@Evmorov Perché non è un clone profondo. Il passaggio 1 sta solo clonando l'array, non gli oggetti all'interno. In altre parole, ciascuno degli oggetti all'interno del nuovo array "punta ancora" agli oggetti esistenti in memoria - mutando l'uno si muterà l'altro (sono uno e lo stesso). Vedi anche il items[0] === clone[0]bit nel mio esempio di terminale in fondo. Triple =controlla se gli oggetti si riferiscono alla stessa cosa.
Aprire il

Diventa più complicato se non si conosce l'indice dell'articolo nell'array.
Ian Warburton,

@IanWarburton Non proprio. items.findIndex()dovrebbe farla breve.
aprono il

92

Senso vietato!

handleChange = (e) => {
    const { items } = this.state;
    items[1].name = e.target.value;

    // update state
    this.setState({
        items,
    });
};

Come sottolineato da molti sviluppatori migliori nei commenti: mutare lo stato è sbagliato!

Mi ci è voluto un po 'per capirlo. Sopra funziona ma toglie il potere di React. Ad esempio componentDidUpdate, questo non lo vedrà come un aggiornamento perché viene modificato direttamente.

Quindi il modo giusto sarebbe:

handleChange = (e) => {
    this.setState(prevState => ({
        items: {
            ...prevState.items,
            [prevState.items[1].name]: e.target.value,
        },
    }));
};

25
ES6 solo perché stai usando "const"?
nkkollaw,

49
Non è chiamare items[1].role = e.target.valuemutare direttamente Stato?
antony

28
stai mutando lo stato, questo è totalmente contrario all'idea di mantenere lo stato immutabile come la reazione suggerita. Questo può darti molto dolore in una grande applicazione.
ncubica,

8
@MarvinVK, la tua risposta dice "Quindi la migliore pratica sarebbe:" seguita dall'uso di "this.forceUpdate ();" che non è raccomandato in quanto potrebbe essere sovrascritto da setState (), consultare facebook.github.io/react/docs/react-component.html#state . Meglio cambiare questo in modo da non confondere i futuri lettori.
James Z.

8
Volevo solo sottolineare che molti commenti sono irrilevanti a causa delle modifiche e il modo giusto è in realtà il modo giusto.
Heez

50

Per modificare oggetti / variabili profondamente annidati nello stato di React, in genere vengono utilizzati tre metodi: JavaScript vanilla Object.assign, immutability-helper e cloneDeepda Lodash .

Ci sono anche molte altre librerie di terze parti meno popolari per raggiungere questo obiettivo, ma in questa risposta tratterò solo queste tre opzioni. Inoltre, esistono altri metodi JavaScript di vaniglia, come la diffusione di array, (vedi la risposta di @ mpen per esempio), ma non sono molto intuitivi, facili da usare e in grado di gestire tutte le situazioni di manipolazione dello stato.

Come è stato sottolineato innumerevoli volte nei commenti più votati alle risposte, i cui autori propongono una mutazione diretta dello stato: proprio non farlo . Questo è un onnipresente anti-pattern di React, che porterà inevitabilmente a conseguenze indesiderate. Impara nel modo giusto.

Confrontiamo tre metodi ampiamente utilizzati.

Data questa struttura di oggetti stato:

state = {
    outer: {
        inner: 'initial value'
    }
}

È possibile utilizzare i seguenti metodi per aggiornare quello più interno inner valore del campo senza influire sul resto dello stato.

1. Object.assign di Vanilla JavaScript

const App = () => {
  const [outer, setOuter] = React.useState({ inner: 'initial value' })

  React.useEffect(() => {
    console.log('Before the shallow copying:', outer.inner) // initial value
    const newOuter = Object.assign({}, outer, { inner: 'updated value' })
    console.log('After the shallow copy is taken, the value in the state is still:', outer.inner) // initial value
    setOuter(newOuter)
  }, [])

  console.log('In render:', outer.inner)

  return (
    <section>Inner property: <i>{outer.inner}</i></section>
  )
}

ReactDOM.render(
  <App />,
  document.getElementById('react')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.10.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.2/umd/react-dom.production.min.js"></script>

<main id="react"></main>

Tieni presente che Object.assign non eseguirà una clonazione approfondita , poiché copia solo i valori delle proprietà ed è per questo che ciò che fa viene chiamato copia superficiale (vedi commenti).

Perché questo funzioni, dovremmo solo manipolare le proprietà dei tipi primitivi ( outer.inner), ovvero stringhe, numeri, valori booleani.

In questo esempio, stiamo creando una nuova costante (const newOuter... ), utilizzando Object.assign, che crea un oggetto vuoto ( {}), copia l' outeroggetto ( { inner: 'initial value' }) in esso e quindi copia un oggetto diverso { inner: 'updated value' } su di esso.

In questo modo, alla fine, la newOutercostante appena creata conterrà un valore { inner: 'updated value' }poiché la innerproprietà è stata sostituita. Questo newOuterè un oggetto nuovo di zecca, che non è collegato all'oggetto in stato, quindi può essere mutato in base alle esigenze e lo stato rimarrà lo stesso e non verrà modificato fino a quando non verrà eseguito il comando per aggiornarlo.

L'ultima parte consiste nell'utilizzare setOuter()setter per sostituire l'originale outernello stato con un newOuteroggetto appena creato (cambia solo il valore, il nome della proprietàouter no).

Ora immagina di avere uno stato più profondo come state = { outer: { inner: { innerMost: 'initial value' } } }. Potremmo provare a creare l' newOuteroggetto e popolarlo con ilouter contenuti dello stato, ma Object.assignnon saremo in grado di copiare innerMostil valore su questo newOuteroggetto appena creato poichéinnerMost è nidificato troppo in profondità.

Potresti comunque copiare inner, come nell'esempio sopra, ma dato che ora è un oggetto e non una primitiva, il riferimento da newOuter.innerverrà copiato nell'oggetto outer.innerinvece, il che significa che finiremo con l' newOuteroggetto locale direttamente legato all'oggetto nello stato .

Ciò significa che in questo caso le mutazioni del creato localmente newOuter.innerinfluenzeranno direttamente l' outer.inneroggetto (nello stato), poiché in realtà sono diventate la stessa cosa (nella memoria del computer).

Object.assign pertanto funzionerà solo se si dispone di una struttura di stato profondo a un livello relativamente semplice con membri più interni che contengono valori di tipo primitivo.

Se hai oggetti più profondi (2 ° livello o più), che dovresti aggiornare, non usare Object.assign . Rischi direttamente lo stato di mutazione.

2. Clone di Lodash Profondo

const App = () => {
  const [outer, setOuter] = React.useState({ inner: 'initial value' })

  React.useEffect(() => {
    console.log('Before the deep cloning:', outer.inner) // initial value
    const newOuter = _.cloneDeep(outer) // cloneDeep() is coming from the Lodash lib
    newOuter.inner = 'updated value'
    console.log('After the deeply cloned object is modified, the value in the state is still:', outer.inner) // initial value
    setOuter(newOuter)
  }, [])

  console.log('In render:', outer.inner)

  return (
    <section>Inner property: <i>{outer.inner}</i></section>
  )
}

ReactDOM.render(
  <App />,
  document.getElementById('react')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.10.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.2/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

<main id="react"></main>

CloneDeep di Lodash è molto più semplice da usare. Esegue una clonazione profonda , quindi è un'opzione solida, se si dispone di uno stato abbastanza complesso con oggetti o matrici multilivello all'interno. Solo cloneDeep()la proprietà dello stato di livello superiore, muta la parte clonata nel modo che preferisci, esetOuter() torna allo stato.

3. aiutante dell'immutabilità

const App = () => {
  const [outer, setOuter] = React.useState({ inner: 'initial value' })
  
  React.useEffect(() => {
    const update = immutabilityHelper
    console.log('Before the deep cloning and updating:', outer.inner) // initial value
    const newOuter = update(outer, { inner: { $set: 'updated value' } })
    console.log('After the cloning and updating, the value in the state is still:', outer.inner) // initial value
    setOuter(newOuter)
  }, [])

  console.log('In render:', outer.inner)

  return (
    <section>Inner property: <i>{outer.inner}</i></section>
  )
}

ReactDOM.render(
  <App />,
  document.getElementById('react')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.10.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.2/umd/react-dom.production.min.js"></script>
<script src="https://wzrd.in/standalone/immutability-helper@3.0.0"></script>

<main id="react"></main>

immutability-helperlo prende ad un livello completamente nuovo, e il bello di tutto ciò è che può non solo $seti valori agli elementi di stato, ma anche $push, $splice, $merge(ecc) di loro. Ecco un elenco di comandi disponibili.

Note a margine

Ancora una volta, tieni presente che ciò setOutermodifica solo le proprietà di primo livello dell'oggetto stato ( outerin questi esempi), non i nidificati in profondità (outer.inner ). Se si comportasse in modo diverso, questa domanda non esisterebbe.

Quale è giusto per il tuo progetto?

Se non si desidera o non si possono utilizzare dipendenze esterne e si dispone di una struttura di stato semplice , attenersi a Object.assign.

Se manipoli uno stato enorme e / o complesso , quella di Lodash cloneDeepè una scelta saggia.

Se hai bisogno di funzionalità avanzate , ad esempio se la tua struttura statale è complessa e devi eseguire tutti i tipi di operazioni su di essa, prova immutability-helper, è uno strumento molto avanzato che può essere utilizzato per la manipolazione dello stato.

... o hai davvero bisogno di farlo?

Se conservi dati complessi nello stato di React, forse è un buon momento per pensare ad altri modi di gestirli. Impostare oggetti di stato complessi proprio nei componenti di React non è un'operazione semplice e suggerisco vivamente di pensare a diversi approcci.

Molto probabilmente faresti meglio a conservare i tuoi dati complessi in un negozio Redux, impostarli lì utilizzando riduttori e / o saghe e accedervi utilizzando i selettori.


Object.assignnon esegue una copia profonda. Dì, se a = {c: {d: 1}}e b = Object.assign({}, a), quindi esegui b.c.d = 4, quindi a.c.dviene modificato.
Awol

Hai ragione, il valore 1dell'oggetto più interno ( a.c.d) verrà mutato. Ma se riassegnerai il successore di primo livello di b, in questo modo b.c = {f: 1}:, la parte corrispondente di anon verrà mutata (rimarrà {d: 1}). Bella cattura comunque, aggiornerò subito la risposta.
Neurotrasmettitore

Quello che hai definito è in realtà un shallow copye non un deep copy. È facile confondere ciò che shallow copysignifica. In shallow copy, a !== bma per ogni chiave dall'oggetto sorgente a,a[key] === b[key]
Awol

Sì, esplicitamente menzionato superficialità Object.assignnella risposta.
Neurotrasmettitore

JSON.parse(JSON.stringify(object))è anche una variante per il clone profondo. Tuttavia, la performance è peggiore di lodash cloneDeep. measurethat.net/Benchmarks/Show/2751/0/…
tylik

35

Ho avuto lo stesso problema. Ecco una soluzione semplice che funziona!

const newItems = [...this.state.items];
newItems[item] = value;
this.setState({ items:newItems });

11
@TranslucentCloud - questa non è certamente una mutazione diretta. l'array originale è stato clonato, modificato e quindi lo stato è stato nuovamente impostato utilizzando l'array clonato.
vsync,

@vsync sì, ora dopo aver modificato la risposta originale questa non è affatto una mutazione.
Neurotrasmettitore,

2
@TranslucentCloud - Anche prima, la mia modifica non ha nulla a che fare con questo, grazie mille per l'atteggiamento. @Jonas qui ha fatto solo un semplice errore nella sua risposta, usando {parentesi graffe invece di parentesi che avevo rimediato
vsync

31

Secondo la documentazione di React su setState , l'utilizzo Object.assigncome suggerito da altre risposte qui non è l'ideale. A causa della natura disetState comportamento asincrono, le chiamate successive che utilizzano questa tecnica possono sovrascrivere le chiamate precedenti causando risultati indesiderati.

Invece, i documenti di React raccomandano di usare il modulo di aggiornamento di setStatecui opera sullo stato precedente. Tenere presente che quando si aggiorna un array o un oggetto è necessario restituire un nuovo array o oggetto poiché React richiede di preservare l'immutabilità dello stato. L'uso dell'operatore spread della sintassi ES6 per copiare superficialmente un array, creare o aggiornare una proprietà di un oggetto in un determinato indice dell'array sarebbe simile al seguente:

this.setState(prevState => {
    const newItems = [...prevState.items];
    newItems[index].name = newName;
    return {items: newItems};
})

2
Questa è la risposta appropriata se si utilizza ES6. È in linea la risposta di @Jonas. Tuttavia a causa della spiegazione si distingue.
Sourabh,

Sì, questo codice funziona perfettamente e uno molto semplice ..
Shoeb Mirza,

29

Per prima cosa prendi l'oggetto che vuoi, cambia quello che vuoi su quell'oggetto e ripristinalo sullo stato. Il modo in cui stai utilizzando lo stato passando solo un oggetto getInitialStatesarebbe molto più semplice se utilizzassi un oggetto con chiave.

handleChange: function (e) {
   item = this.state.items[1];
   item.name = 'newName';
   items[1] = item;

   this.setState({items: items});
}

3
No, cede Uncaught TypeError: Cannot read property 'items' of null.
martins,

No non lo farà. Molto probabilmente il tuo errore deriva dal modo in cui stai facendo getInitialState.
Henrik Andersson,

10
@HenrikAndersson Qualcosa non sembra giusto nel tuo esempio. itemsnon è definito da nessuna parte.
Edward D'Souza,

1
@ EdwardD'Souza Hai assolutamente ragione! La mia risposta è mostrare come dovrebbe essere definito e usato. Il modo in cui il codice del richiedente viene impostato non funziona per ciò che vorrebbe e per questo motivo è necessaria la necessità di un oggetto con chiave.
Henrik Andersson,

7
Questo è un tipico anti-pattern di React, stai assegnando itemun riferimento alla this.state.items[1]variabile dello stato . Quindi modifichi item( item.name = 'newName') e quindi muti direttamente lo stato, il che è altamente scoraggiato. Nel tuo esempio, non è nemmeno necessario chiamare this.setState({items: items}), perché lo stato è già direttamente mutato.
Neurotrasmettitore

22

Non mutare lo stato in atto. Può causare risultati imprevisti. Ho imparato la mia lezione! Lavora sempre con una copia / clone, Object.assign()è buono:

item = Object.assign({}, this.state.items[1], {name: 'newName'});
items[1] = item;
this.setState({items: items});

https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign


8
cosa c'è itemsnel tuo esempio? Intendevi this.state.itemso qualcos'altro?
Buh Buh,

Ho provato questo ma manca una riga. Sopra items[1] = item;dovrebbe esserci una frase che dice items = this.state.items;. Attenzione, il mio javascript è arrugginito e sto imparando a reagire per il mio progetto di casa, quindi non ho idea se questo è buono o cattivo :-)
Greg0ry

4

È davvero semplice

Prima estrae l'intero oggetto item dallo stato, aggiorna la parte dell'oggetto items come desiderato e riporta l'intero oggetto item nello stato tramite setState.

handleChange: function (e) {
  items = Object.assign(this.state.items); // Pull the entire items object out. Using object.assign is a good idea for objects.
  items[1].name = 'newName'; // update the items object as needed
  this.setState({ items }); // Put back in state
}

"Object.assign funzionerà se si dispone di una struttura di stato profondo a un livello relativamente semplice con membri più interni che contengono valori di tipo primitivo".
Neurotrasmettitore

3

Dato che nessuna delle opzioni precedenti era l'ideale per me, ho finito per usare map:

this.setState({items: this.state.items.map((item,idx)=> idx!==1 ?item :{...item,name:'new_name'}) })

2

Mutazione gratuita:

// given a state
state = {items: [{name: 'Fred', value: 1}, {name: 'Wilma', value: 2}]}

// This will work without mutation as it clones the modified item in the map:
this.state.items
   .map(item => item.name === 'Fred' ? {...item, ...{value: 3}} : item)

this.setState(newItems)

2
Non riesco a vedere dove newItemsè impostato.
Neurotrasmettitore

Una mappa e un confronto nell'array non sono orribili per le prestazioni?
Natassia Tavares,

@NatassiaTavares .. cosa? forse sei confuso fo ofo la forEachmappa è la più veloce.
Deano,

1

Ho trovato questo sorprendentemente duro e nessuna delle magie ES6 sembrava funzionare come previsto. Stava usando una struttura come questa per ottenere le proprietà degli elementi renderizzate ai fini del layout.

trovato usando il updatemetodo from immutability-helperper essere il più diretto in questo esempio semplificato:

constructor(props) {
    super(props)
    this.state = { values: [] }
    this.updateContainerState = this.updateContainerState.bind(this)
  }

updateContainerState(index, value) {
    this.setState((state) => update(state, { values: { [index]: { $set: value } } }))
  }

adattato da https://github.com/kolodny/immutability-helper#computed-property-names

del membro dell'array da aggiornare è un oggetto complesso più nidificato che utilizza il metodo di copia approfondita appropriato base alla complessità.

Esistono sicuramente modi migliori per gestire i parametri di layout, ma si tratta di come gestire gli array. I valori rilevanti per ciascun elemento figlio potrebbero anche essere calcolati al di fuori di essi, ma ho trovato più conveniente passare containerState in giù, in modo che i bambini possano recuperare le proprietà a piacimento e aggiornare l'array di stato padre nel loro indice dato.

import React from 'react'
import update from 'immutability-helper'
import { ContainerElement } from './container.component.style.js'
import ChildComponent from './child-component'
export default class ContainerComponent extends React.Component {
  constructor(props) {
    super(props)
    this.state = { values: [] }
    this.updateContainerState = this.updateContainerState.bind(this)
  }

  updateContainerState(index, value) {
    this.setState((state) => update(state, { values: { [index]: { $set: value } } }))
  }

  // ...

  render() {
    let index = 0
    return (
      <ContainerElement>
      <ChildComponent
        index={index++}
        containerState={this.state}
        updateContainerState={this.updateContainerState}
      />
      <ChildComponent
        index={index++}
        containerState={this.state}
        updateContainerState={this.updateContainerState}
      />
      </ContainerElement>
    )
  }
}

1

Usa la mappa dell'array con la funzione freccia, su una riga

this.setState({
    items: this.state.items.map((item, index) =>
      index === 1 ? { ...item, name: 'newName' } : item,
   )
})

1
Questo è sostanzialmente identico a questa altra risposta postata circa un anno fa
CertainPerformance

0

Utilizzare l'evento on handleChangeper capire l'elemento che è stato modificato e quindi aggiornarlo. Per questo potrebbe essere necessario modificare alcune proprietà per identificarlo e aggiornarlo.

Vedi violino https://jsfiddle.net/69z2wepo/6164/


0

Vorrei spostare la modifica dell'handle di funzione e aggiungere un parametro di indice

handleChange: function (index) {
    var items = this.state.items;
    items[index].name = 'newName';
    this.setState({items: items});
},

al componente Modulo dinamico e passalo al componente PopulateAtCheckboxes come prop. Mentre esegui il ciclo sugli articoli, puoi includere un contatore aggiuntivo (chiamato indice nel codice seguente) da passare alla modifica della maniglia come mostrato di seguito

{ Object.keys(this.state.items).map(function (key, index) {
var item = _this.state.items[key];
var boundHandleChange = _this.handleChange.bind(_this, index);
  return (
    <div>
        <PopulateAtCheckboxes this={this}
            checked={item.populate_at} id={key} 
            handleChange={boundHandleChange}
            populate_at={data.populate_at} />
    </div>
);
}, this)}

Finalmente puoi chiamare il tuo listener di modifiche come mostrato qui sotto

<input type="radio" name={'populate_at'+this.props.id} value={value} onChange={this.props.handleChange} checked={this.props.checked == value} ref="populate-at"/>

Non mutare mai direttamente lo stato di React.
Neurotrasmettitore

0

Se è necessario modificare solo una parte di Array, È necessario un componente di reazione con stato impostato su.

state = {items: [{name: 'red-one', value: 100}, {name: 'green-one', value: 999}]}

È meglio aggiornare il red-onenel modo Arrayseguente:

const itemIndex = this.state.items.findIndex(i=> i.name === 'red-one');
const newItems = [
   this.state.items.slice(0, itemIndex),
   {name: 'red-one', value: 666},
   this.state.items.slice(itemIndex)
]

this.setState(newItems)

che cos'è newArray? intendi newItems? Se lo fai, non lascerebbe lo stato con un solo oggetto in seguito?
micnil,

Questo introdurrà una nuova proprietà newItemsper l' stateoggetto, e non aggiornerà l'attuale itemsproprietà.
Neurotrasmettitore

0

o se hai un elenco generato dinamicamente e non conosci l'indice ma hai solo la chiave o l'id:

let ItemsCopy = []
let x = this.state.Items.map((entry) =>{

    if(entry.id == 'theIDYoureLookingFor')
    {
        entry.PropertyToChange = 'NewProperty'
    }

    ItemsCopy.push(entry)
})


this.setState({Items:ItemsCopy});

0

Prova con il codice:

this.state.items[1] = 'new value';
var cloneObj = Object.assign({}, this.state.items);

this.setState({items: cloneObj });

0

Il seguente pezzo di codice è diventato facile nel mio cervello noioso. Rimozione dell'oggetto e sostituzione con quello aggiornato

    var udpateditem = this.state.items.find(function(item) { 
                   return item.name == "field_1" });
    udpateditem.name= "New updated name"                       
    this.setState(prevState => ({                                   
    items:prevState.dl_name_template.filter(function(item) { 
                                    return item.name !== "field_1"}).concat(udpateditem)
    }));

0

Che ne dici di creare un altro componente (per un oggetto che deve andare nell'array) e passare i seguenti come oggetti di scena?

  1. indice componente: l'indice verrà utilizzato per creare / aggiornare nell'array.
  2. funzione set: questa funzione inserisce i dati nell'array in base all'indice del componente.
<SubObjectForm setData={this.setSubObjectData}                                                            objectIndex={index}/>

Qui {indice} può essere passato in base alla posizione in cui viene utilizzato questo SubObjectForm.

e setSubObjectData può essere qualcosa del genere.

 setSubObjectData: function(index, data){
      var arrayFromParentObject= <retrieve from props or state>;
      var objectInArray= arrayFromParentObject.array[index];
      arrayFromParentObject.array[index] = Object.assign(objectInArray, data);
 }

In SubObjectForm, this.props.setData può essere chiamato alla modifica dei dati come indicato di seguito.

<input type="text" name="name" onChange={(e) => this.props.setData(this.props.objectIndex,{name: e.target.value})}/>

0
this.setState({
      items: this.state.items.map((item,index) => {
        if (index === 1) {
          item.name = 'newName';
        }
        return item;
      })
    });

1
questo non è quindi ottimale, ripetete l'intero array per aggiornare solo il secondo elemento?
wscourge

Stai anche mutando l'elemento nel primo array, dovresti usareitem = Object.assign({}, item, {name: 'newName'});
remram il

0

@La risposta di JonnyBuchanan funziona perfettamente, ma solo per la variabile di stato dell'array. Nel caso in cui la variabile di stato sia solo un singolo dizionario, segui questo:

inputChange = input => e => {
    this.setState({
        item: update(this.state.item, {[input]: {$set: e.target.value}})
    })
}

Puoi sostituirlo [input]con il nome del campo del tuo dizionario e e.target.valuecon il suo valore. Questo codice esegue il processo di aggiornamento sull'evento di modifica input del mio modulo.


-3

Prova questo funzionerà sicuramente, nell'altro caso ho provato ma non ha funzionato

import _ from 'lodash';

this.state.var_name  = _.assign(this.state.var_name, {
   obj_prop: 'changed_value',
});

Non mutare mai direttamente lo stato di React.
Neurotrasmettitore

-3
 handleChanges = (value, key) => {
     // clone the current State object
    let cloneObject = _.extend({}, this.state.currentAttribute);
    // key as user.name and value= "ABC" then current attributes have current properties as we changes
    currentAttribute[key] = value;
    // then set the state "currentAttribute" is key and "cloneObject" is changed object.  
    this.setState({currentAttribute: cloneObject});

e Cambia dalla casella di testo aggiungi l'evento onChange

onChange = {
   (event) => {                                                
      this.handleChanges(event.target.value, "title");
   }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.