2015-10-01 4 views

risposta

7

È possibile impostare foo-undefined, in questo modo

var Hello = React.createClass({ 
    getInitialState: function() { 
     return { 
      foo: 10, 
      bar: 10 
     } 
    }, 

    handleClick: function() { 
     this.setState({ foo: undefined }); 
    }, 

    render: function() { 
     return (
      <div> 
       <div onClick={ this.handleClick.bind(this) }>Remove foo</div> 
       <div>Foo { this.state.foo }</div> 
       <div>Bar { this.state.bar }</div> 
      </div> 
     ); 
    } 
}); 

Example

Inoltre è possibile utilizzare delete,

delete this.state.foo; 
this.setState(this.state); 

ma questo è pericoloso perché questa soluzione manipola direttamente this.state

Aggiornamento

La soluzione precedente è sufficiente rimuovere il valore da foo e key abilità esiste in state, se avete bisogno di rimuovere completamente chiave dal state, una delle possibili soluzioni può essere setState con un genitore key, in questo modo

var Hello = React.createClass({ 
 
    getInitialState: function() { 
 
    return { 
 
     data: { 
 
     foo: 10, 
 
     bar: 10 
 
     } 
 
    } 
 
    }, 
 
    \t 
 
    handleClick: function() { 
 
    const state = { 
 
     data: _.omit(this.state.data, 'foo') 
 
    }; 
 
    
 
    this.setState(state,() => { 
 
     console.log(this.state); 
 
    }); 
 
    }, 
 
     
 
    render: function() { 
 
    return (
 
     <div> 
 
     <div onClick={ this.handleClick }>Remove foo</div> 
 
     <div>Foo { this.state.data.foo }</div> 
 
     <div>Bar { this.state.data.bar }</div> 
 
     </div> 
 
    ); 
 
    } 
 
}); 
 

 
ReactDOM.render(<Hello />, document.getElementById('container'))
<script src="https://cdn.jsdelivr.net/lodash/4.17.4/lodash.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> 
 
<div id="container"></div>

2

Soluzione precedente - è antipattern, perché cambia this.state. È sbagliato!

Utilizzare questa (vecchia maniera):

let newState = Object.assign({}, this.state) // Copy state 
newState.foo = null // modyfy copyed object, not original state 
// newState.foo = undefined // works too 
// delete newState.foo // Wrong, do not do this 
this.setState(newState) // set new state 

Oppure utilizzare ES6 zucchero:

this.setState({...o, a:undefined}) 

Abbastanza dolce, non è vero?))

Nella vecchia Reagire sintassi (originale, non ES6), questo ha this.replaceState, che rimuove le chiavi inutili in negozio, ma ora è deprecated

+0

Entrambe queste soluzioni sono anche sbagliate. La prima ragione è che, 'Object.assign()' [non farà un clone profondo] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign #Deep_Clone), quindi potresti finire direttamente modificando lo stato senza utilizzare app più complesse. Il secondo problema si verifica in entrambe le soluzioni ed è lo stesso della risposta di @ alexander-t. Non stai rimuovendo la chiave da 'Object.keys()' come richiesto. Stai solo cambiando il suo valore. – Vince

+0

Sì, conosco Object.keys, ma la mia risposta risolve un problema. E hai un brutto carattere come se mi inabissasse due volte. – MiF

+0

Questo argomento non ha alcun significato emotivo per me e nessuno può votare due volte. Ho votato una volta la tua risposta perché non risolve il problema posto dalla domanda. Non sono sicuro di come questo risolva alcun problema, comunque. Se si itera su proprietà dell'oggetto stato per creare un elenco o una tabella, impostando il valore di uno di essi su 'null' /' indefinito' si genera almeno un elemento di elenco vuoto o una riga di tabella. Se il codice viene scritto per utilizzare le proprietà degli oggetti figlio, l'impostazione del valore su 'null' /' indefinito' comporterà errori difficili da risolvere. – Vince

1

È possibile utilizzare Object.assign per fare una copia dello stato dell'applicazione alla profondità corretta ed elimina l'elemento dalla tua copia. Quindi utilizzare setState per unire nuovamente la copia modificata nello stato dell'applicazione.

Questa non è una soluzione perfetta. Copiare un intero oggetto come questo potrebbe portare a problemi di prestazioni/memoria. La copia superficiale di Object.assign aiuta ad alleviare i problemi di memoria/prestazioni, ma è anche necessario sapere quali parti del nuovo oggetto sono copie e quali parti sono riferimenti a dati nello stato dell'applicazione.

Nell'esempio seguente, la modifica dell'array ingredients potrebbe effettivamente modificare direttamente lo stato dell'applicazione.

L'impostazione del valore dell'elemento indesiderato su null o undefined non viene rimossa.

const Component = React.Component; 
 

 
class App extends Component { 
 
    constructor(props) { 
 
    super(props); 
 
    this.state = { 
 
     "recipes": { 
 
     "1": { 
 
      "id": 1, 
 
      "name": "Pumpkin Pie", 
 
      "ingredients": [ 
 
      "Pumpkin Puree", 
 
      "Sweetened Condensed Milk", 
 
      "Eggs", 
 
      "Pumpkin Pie Spice", 
 
      "Pie Crust" 
 
      ] 
 
     }, 
 
     "2": { 
 
      "id": 2, 
 
      "name": "Spaghetti", 
 
      "ingredients": [ 
 
      "Noodles", 
 
      "Tomato Sauce", 
 
      "(Optional) Meatballs" 
 
      ] 
 
     }, 
 
     "3": { 
 
      "id": 3, 
 
      "name": "Onion Pie", 
 
      "ingredients": [ 
 
      "Onion", 
 
      "Pie Crust", 
 
      "Chicken Soup Stock" 
 
      ] 
 
     }, 
 
     "4": { 
 
      "id": 4, 
 
      "name": "Chicken Noodle Soup", 
 
      "ingredients": [ 
 
      "Chicken", 
 
      "Noodles", 
 
      "Chicken Stock" 
 
      ] 
 
     } 
 
     }, 
 
     "activeRecipe": "4", 
 
     "warningAction": { 
 
     "name": "Delete Chicken Noodle Soup", 
 
     "description": "delete the recipe for Chicken Noodle Soup" 
 
     } 
 
    }; 
 
    
 
    this.renderRecipes = this.renderRecipes.bind(this); 
 
    this.deleteRecipe = this.deleteRecipe.bind(this); 
 
    } 
 
    
 
    deleteRecipe(e) { 
 
    const recipes = Object.assign({}, this.state.recipes); 
 
    const id = e.currentTarget.dataset.id; 
 
    delete recipes[id]; 
 
    this.setState({ recipes }); 
 
    } 
 
    
 
    renderRecipes() { 
 
    const recipes = []; 
 
    for (const id in this.state.recipes) { 
 
     recipes.push((
 
     <tr> 
 
      <td> 
 
      <button type="button" data-id={id} onClick={this.deleteRecipe} 
 
      >&times;</button> 
 
      </td> 
 
      <td>{this.state.recipes[id].name}</td> 
 
     </tr> 
 
    )); 
 
    } 
 
    return recipes; 
 
    } 
 
       
 
    render() { 
 
    return (
 
     <table> 
 
     {this.renderRecipes()} 
 
     </table> 
 
    ); 
 
    } 
 
} 
 

 
ReactDOM.render(<App />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> 
 
<main id="app"></main>

2

Il seguente codice rimuoverà foo da this.state senza mutare direttamente this.state:

const {foo, ...state} = this.state; 
this.setState({state}); 

sarà necessario il stage 3 preset per far funzionare tutto questo.

+0

Questo ha richiesto un po 'di lettura per capire. Riconosco la destrutturazione, ma non l'ho usata molto. L'operatore di spread [diventa un livello profondo] (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Spread_operator#Copy_an_array), proprio come 'Object.assign'. Quindi, è effettivamente la stessa della mia soluzione con 'Object.assign', ma richiede un'ulteriore configurazione di Babel per funzionare. – Vince

+1

La clonazione superficiale è OK e, di fatto, è ottimizzata perché è veloce. Finché segui le regole intorno a ciò che dovrebbe essere immutabile, va bene. La libreria 'immutability-helper', che i documenti React raccomandano in sostituzione di' react-addons-update', fa la stessa cosa. –

+0

Un sacco di persone usano i preset della fase n. La fase 3 è piuttosto conservativa. Questo funzionerà in tutte le fasi fino al 3 incluso. –

0

In ReactCompositeComponent.js nella sorgente React su GitHub è un metodo chiamato _processPendingState, che è il metodo definitivo che implementa lo stato di unione dalle chiamate a component.setState;

`` ` _processPendingState: function (props, context) { var inst = this._instance; var queue = this._pendingStateQueue; var replace = this._pendingReplaceState; this._pendingReplaceState = false; this._pendingStateQueue = null;

if (!queue) { 
    return inst.state; 
} 

if (replace && queue.length === 1) { 
    return queue[0]; 
} 

var nextState = replace ? queue[0] : inst.state; 
var dontMutate = true; 
for (var i = replace ? 1 : 0; i < queue.length; i++) { 
    var partial = queue[i]; 
    let partialState = typeof partial === 'function' 
    ? partial.call(inst, nextState, props, context) 
    : partial; 
    if (partialState) { 
    if (dontMutate) { 
     dontMutate = false; 
     nextState = Object.assign({}, nextState, partialState); 
    } else { 
     Object.assign(nextState, partialState); 
    } 
    } 
} 

`` `

In questo codice è possibile vedere la linea attuale che implementa l'unione;

nextState = Object.assign({}, nextState, partialState); 

nessuna parte in questa funzione c'è una chiamata a delete o simili, il che significa che non è realmente inteso comportamento. Inoltre, copiare completamente la statistica, eliminare la proprietà e chiamare setState non funzionerà perché setState è sempre un'unione, quindi la proprietà eliminata verrà semplicemente ignorata.

Si noti inoltre che setState non funziona immediatamente, ma i lotti cambiano, quindi se si tenta di clonare l'intero oggetto stato e si effettua solo una modifica di una proprietà, è possibile cancellare le chiamate precedenti su setState. Come dice il documento React;

React può eseguire il batch di più chiamate setState() in un singolo aggiornamento per prestazioni.

Poiché this.props e this.state possono essere aggiornati in modo asincrono, non si deve fare affidamento sui loro valori per calcolare lo stato successivo.

Quello che potresti cercare è aggiungere ulteriori informazioni;

this.setState({ xSet: true, x: 'foo' }); 
this.setState({ xSet: false, x: undefined }); 

Questo è brutto, scontato, ma ti dà l'ulteriore pezzo di informazioni è necessario distinguere tra un valore impostato su undefined, e un valore non impostato a tutti. Inoltre, funziona bene con gli interni di React, le transazioni, il cambio di stato, il batching e qualsiasi altro horror.Meglio prendere un po 'di complessità extra qui che provare a ritorsioni secondarie interne, che sono piene di orrori come la riconciliazione delle transazioni, la gestione di funzionalità deprecate come replaceState, ecc.

0

Se la rimozione è in una funzione e la chiave deve essere una variabile, prova questo:

removekey = (keyname) => { 
    let newState = this.state; 
    delete newState[keyname]; 
    this.setState({ newState }) 
} 

this.removekey('thekey'); 

Quasi uguale alla risposta di steve, ma in una funzione.