2015-06-09 23 views
10

Considerate questo esempio:Reagire - cambiare defaultValue ingresso da puntelli che passano

var Field = React.createClass({ 
    render: function() { 
     // never renders new value... 
     return (
      <div> 
       <input type="text" defaultValue={this.props.value || ''} /> 
      </div> 
     ); 
    } 
}); 

var App = React.createClass({ 
    getInitialState: function() { 
     return {value: 'Hello!'}; 
    }, 

    changeTo: function (str) { 
     this.setState({value: str}); 
    }, 

    render: function() { 
     return (
      <div> 
       <Field value={this.state.value} /> 
       <button onClick={this.changeTo.bind(null, 'Whyyyy?')}>Change to "Whyyyy?"</button> 
       <button onClick={this.changeTo.bind(null, void 0)}>Change to undefined</button> 
      </div> 
     ); 
    } 
}); 

React.render(
    <App />, 
    document.getElementById('app') 
); 

voglio passare valore nella defaultValue come puntello della componente di ingresso muto. Tuttavia non lo rivisita mai.

+0

Leggi https://facebook.github.io/react/docs/forms.html#advanced-topics perché questo sta accadendo. –

+0

Possibile duplicato di [Input React defaultValue non si aggiorna con stato] (http://stackoverflow.com/questions/30146105/react-input-defaultvalue-doesnt-update-with-state) – Manolo

risposta

3

Sono abbastanza certo che questo ha a che fare con Controlled vs. Uncontrolled inputs.

Se ho capito bene, dal momento che il tuo <input> non è controllato (non definisce un attributo value), il valore verrà sempre risolto con il valore con il quale è stato inizializzato. In questo caso Hello!.

Per ovviare a questo problema, è possibile aggiungere un attributo value e impostarlo durante la onChange:

var Field = React.createClass({ 
     render: function() { 
      // never renders new value... 
      return (
       <div> 
        <input type="text" defaultValue={this.props.default || ''} value={this.props.value} /> 
       </div> 
     ); 
     } 
    }); 

Here is a plunker che mostra il cambiamento.

+0

È questo il modo più pulito per risolvere input incontrollati? Inoltre non vedo alcuna funzione 'onChange' sul tuo esempio. – JohnnyQ

+0

@JohnnyQ I componenti non controllati non necessitano di un 'onChange'. Di solito, il valore viene estratto usando un 'ref'. –

+0

Splendid, c'è un bug con l'impostazione del valore e altri tasti come onKeyUp/onKeyPress, quindi se U ha bisogno, in alcune circostanze, dell'evento onKeyUp per ex, dovresti impostare onChange sulla stessa funzione, altrimenti l'attributo value non sarà aggiornato. –

10

defaultValue funziona solo per il caricamento iniziale. Dopo questo, non verrà aggiornato. È necessario mantenere lo stato per voi Campo componente:

var Field = React.createClass({ 
    //transfer props to state on load 
    getInitialState: function() { 
     return {value: this.props.value}; 
    }, 
    //if the parent component updates the prop, force re-render 
    componentWillReceiveProps: function(nextProps) { 
     this.setState({value: nextProps.value}); 
    }, 
    //re-render when input changes 
    _handleChange: function (e){ 
     this.setState({value: e.target.value}); 
    }, 
    render: function() { 
     // render based on state 
     return (
      <div> 
       <input type="text" onChange={this._handleChange} 
            value={this.state.value || ''} /> 
      </div> 
     ); 
    } 
}); 
0

ho anche affrontare questo problema, quello che ho fatto è stato quello di aggiornare manualmente il valore di ingresso quando gli oggetti di scena è cambiata. Aggiungi questo al vostro campo reagire classe:

componentWillReceiveProps(nextProps){ 
    if(nextProps.value != this.props.value) { 
     document.getElementById(<element_id>).value = nextProps.value 
    } 
} 

Hai solo bisogno di aggiungere un attributo id per il vostro elemento in modo che possa essere individuato.

+1

Questo rompe la filosofia React Penso che – David

0

il problema è qui:

onClick={this.changeTo.bind(null, 'Whyyyy?')} 

Sono curioso di sapere perchè si associa a null.

Si desidera associare a "questo", in modo che changeTo setState in THIS object.

Prova questa

<button onClick={this.changeTo.bind(this, 'Whyyyy?')}>Change to "Whyyyy?"</button> 
<button onClick={this.changeTo.bind(this, void 0)}>Change to undefined</button> 

in JavaScript, quando viene chiamata una funzione, la sua chiamata nel campo di applicazione in cui è stato chiamato da, non dove è stato scritto (lo so, sembra contro intuitiva). Per assicurarti che venga chiamato nel contesto in cui lo scrivi, devi ".bind (this)".

Per saperne di più su di legame e la portata di funzione, ci sono un sacco di costi- on-line, (alcuni molto meglio di altri) - si potrebbe come questo: http://ryanmorr.com/understanding-scope-and-context-in-javascript/

Consiglio anche utilizzando gli strumenti Dev Reagire se siete utilizzando Firefox o Chrome, in questo modo si sarebbe stato in grado di vedere che state.message non stava cambiando: https://facebook.github.io/react/blog/2015/09/02/new-react-developer-tools.html

25

come una risposta precedente accennato, defaultValue solo viene impostata sul carico iniziale per un modulo. Dopodiché, non verrà aggiornato "naturalmente" perché l'intento era solo quello di impostare un valore predefinito iniziale.

È possibile aggirare il problema se è necessario passando un key alla componente wrapper, come sul componente Field o App, anche se in circostanze più pratici, sarebbe probabilmente un componente form. Un buon key sarebbe un valore univoco per la risorsa che viene passata al form, ad esempio l'id memorizzata nel database.

Nel tuo caso semplificato, si potrebbe fare questo nel tuo campo di rendering:

<div key={this.props.value}> 
    <input type="text" defaultValue={this.props.value || ''} /> 
</div> 

In un caso forma più complessa, qualcosa di simile potrebbe ottenere quello che vuoi, se, ad esempio, la vostra azione onSubmit sottoposto ad un API ma rimase sulla stessa pagina:

const Form = ({item, onSubmit}) => { 
    return (
    <form onSubmit={onSubmit} key={item.id}> 
     <label> 
     First Name 
     <input type="text" name="firstName" defaultValue={item.firstName} /> 
     </label> 
     <label> 
     Last Name 
     <input type="text" name="lastName" defaultValue={item.lastName} /> 
     </label> 
     <button>Submit!</button> 
    </form> 
) 
} 

Form.defaultProps = { 
    item: {} 
} 

Form.propTypes = { 
    item: PropTypes.object, 
    onSubmit: PropTypes.func.isRequired 
} 

quando si utilizzano gli ingressi di forma non controllati, in genere non si preoccupano i valori fino a dopo che sono stati presentati, ecco perché è più ideale per vigore solo un ri-renderizzare quando vuoi davvero aggiornare i valori predefiniti (dopo l'invio, non su ogni cambiamento del singolo input).

Se si modifica anche lo stesso modulo e si teme che la risposta dell'API possa tornare con valori diversi, è possibile fornire una chiave combinata di qualcosa come id più timestamp.

+2

questa dovrebbe essere la migliore risposta –

Problemi correlati