react practicas mejores estados entender ejemplos componentes como javascript forms reactjs coffeescript 2-way-object-databinding

javascript - practicas - Reaccionar entrada defaultValue no se actualiza con el estado



react js ejemplos (5)

Estoy tratando de crear un formulario simple con react, pero tengo dificultades para que los datos se vinculen correctamente con el Valor predeterminado del formulario.

El comportamiento que estoy buscando es este:

  1. Cuando abro mi página, el campo de entrada de texto debe completarse con el texto de mi AwayMessage en mi base de datos. Eso es "Texto de muestra"
  2. Idealmente, quiero tener un marcador de posición en el campo de entrada de texto si AwayMessage en mi base de datos no tiene texto.

Sin embargo, en este momento, encuentro que el campo de entrada de texto está en blanco cada vez que actualizo la página. (Aunque lo que escribo en la entrada se guarda correctamente y persiste). Creo que esto se debe a que el html del campo de texto de entrada se carga cuando AwayMessage es un objeto vacío, pero no se actualiza cuando se carga awayMessage. Además, no puedo especificar un valor predeterminado para el campo.

Eliminé parte del código para mayor claridad (es decir, onToggleChange)

window.Pages ||= {} Pages.AwayMessages = React.createClass getInitialState: -> App.API.fetchAwayMessage (data) => @setState awayMessage:data.away_message {awayMessage: {}} onTextChange: (event) -> console.log "VALUE", event.target.value onSubmit: (e) -> window.a = @ e.preventDefault() awayMessage = {} awayMessage["master_toggle"]=@refs["master_toggle"].getDOMNode().checked console.log "value of text", @refs["text"].getDOMNode().value awayMessage["text"]=@refs["text"].getDOMNode().value @awayMessage(awayMessage) awayMessage: (awayMessage)-> console.log "I''m saving", awayMessage App.API.saveAwayMessage awayMessage, (data) => if data.status == ''ok'' App.modal.closeModal() notificationActions.notify("Away Message saved.") @setState awayMessage:awayMessage render: -> console.log "AWAY_MESSAGE", this.state.awayMessage awayMessageText = if this.state.awayMessage then this.state.awayMessage.text else "Placeholder Text" `<div className="away-messages"> <div className="header"> <h4>Away Messages</h4> </div> <div className="content"> <div className="input-group"> <label for="master_toggle">On?</label> <input ref="master_toggle" type="checkbox" onChange={this.onToggleChange} defaultChecked={this.state.awayMessage.master_toggle} /> </div> <div className="input-group"> <label for="text">Text</label> <input ref="text" onChange={this.onTextChange} defaultValue={awayMessageText} /> </div> </div> <div className="footer"> <button className="button2" onClick={this.close}>Close</button> <button className="button1" onClick={this.onSubmit}>Save</button> </div> </div>

mi console.log para AwayMessage muestra lo siguiente:

AWAY_MESSAGE Object {} AWAY_MESSAGE Object {id: 1, company_id: 1, text: "Sample Text", master_toggle: false}


defaultValue es solo para la carga inicial

Si desea inicializar la entrada, debe usar defaultValue, pero si desea usar el estado para cambiar el valor, debe usar el valor. Personalmente, me gusta usar defaultValue si solo lo estoy inicializando y luego solo usar referencias para obtener el valor cuando lo envíe. Hay más información sobre referencias y entradas en los documentos de reacción, https://facebook.github.io/react/docs/forms.html y https://facebook.github.io/react/docs/working-with-the-browser.html .

Así es como reescribiría su entrada:

awayMessageText = if this.state.awayMessage then this.state.awayMessage.text else '''' <input ref="text" onChange={this.onTextChange} placeholder="Placeholder Text" value={@state.awayMessageText} />

Además, no desea pasar el texto del marcador de posición como lo hizo porque eso realmente establecerá el valor en ''texto de marcador de posición''. Todavía necesita pasar un valor en blanco en la entrada porque undefined y nil convierte el valor en defaultValue esencialmente. https://facebook.github.io/react/tips/controlled-input-null-value.html .

getInitialState no puede hacer llamadas api

Debe realizar llamadas api después de ejecutar getInitialState. Para su caso, lo haría en componentDidMount. Siga este ejemplo, https://facebook.github.io/react/tips/initial-ajax.html .

También recomendaría leer sobre el ciclo de vida del componente con react. https://facebook.github.io/react/docs/component-specs.html .

Reescribir con modificaciones y estado de carga

Personalmente, no me gusta hacer el todo si no es lógica en el renderizado y prefiero usar ''cargar'' en mi estado y renderizar un spinner de fuente impresionante antes de que se cargue el formulario, http://fortawesome.github.io/Font-Awesome/examples/ . Aquí hay una reescritura para mostrarle lo que quiero decir. Si estropeé los ticks para cjsx, es porque normalmente solo uso coffeescript como este,.

window.Pages ||= {} Pages.AwayMessages = React.createClass getInitialState: -> { loading: true, awayMessage: {} } componentDidMount: -> App.API.fetchAwayMessage (data) => @setState awayMessage:data.away_message, loading: false onToggleCheckbox: (event)-> @state.awayMessage.master_toggle = event.target.checked @setState(awayMessage: @state.awayMessage) onTextChange: (event) -> @state.awayMessage.text = event.target.value @setState(awayMessage: @state.awayMessage) onSubmit: (e) -> # Not sure what this is for. I''d be careful using globals like this window.a = @ @submitAwayMessage(@state.awayMessage) submitAwayMessage: (awayMessage)-> console.log "I''m saving", awayMessage App.API.saveAwayMessage awayMessage, (data) => if data.status == ''ok'' App.modal.closeModal() notificationActions.notify("Away Message saved.") @setState awayMessage:awayMessage render: -> if this.state.loading `<i className="fa fa-spinner fa-spin"></i>` else `<div className="away-messages"> <div className="header"> <h4>Away Messages</h4> </div> <div className="content"> <div className="input-group"> <label for="master_toggle">On?</label> <input type="checkbox" onChange={this.onToggleCheckbox} checked={this.state.awayMessage.master_toggle} /> </div> <div className="input-group"> <label for="text">Text</label> <input ref="text" onChange={this.onTextChange} value={this.state.awayMessage.text} /> </div> </div> <div className="footer"> <button className="button2" onClick={this.close}>Close</button> <button className="button1" onClick={this.onSubmit}>Save</button> </div> </div>

Eso debería cubrirlo. Ahora, esa es una forma de avanzar en los formularios que usan estado y valor. También puede usar defaultValue en lugar de value y luego usar referencias para obtener los valores cuando envíe. Si sigue esa ruta, le recomendaría que tenga un componente de capa externa (generalmente denominado componentes de alto orden) para obtener los datos y luego pasarlos al formulario como accesorios.

En general, recomendaría leer los documentos de reacción hasta el final y hacer algunos tutoriales. Hay muchos blogs y http://www.egghead.io tenía algunos buenos tutoriales. También tengo algunas cosas en mi sitio, http://www.openmindedinnovations.com .


Dar valor al parámetro "placeHolder". Por ejemplo :-

<input type="text" placeHolder="Search product name." style={{border:''1px solid #c5c5c5'', padding:font*0.005,cursor:''text''}} value={this.state.productSearchText} onChange={this.handleChangeProductSearchText} />


La forma más confiable de establecer valores iniciales es usar componentDidMount () {} además de render () {}:

... componentDidMount(){ const {nameFirst, nameSecond, checkedStatus} = this.props; document.querySelector(''.nameFirst'').value = nameFirst; document.querySelector(''.nameSecond'').value = nameSecond; document.querySelector(''.checkedStatus'').checked = checkedStatus; return; } ...

Puede resultarle fácil destruir un elemento y reemplazarlo por uno nuevo con

<input defaultValue={this.props.name}/>

Me gusta esto:

if(document.querySelector("#myParentElement")){ ReactDOM.unmountComponentAtNode(document.querySelector("#myParentElement")); ReactDOM.render( <MyComponent name={name} />, document.querySelector("#myParentElement") ); };

También puede usar esta versión del método de desmontaje:

ReactDOM.unmountComponentAtNode(ReactDOM.findDOMNode(this).parentNode);


Otra forma de solucionar esto es cambiando la key de la entrada.

<input ref="text" key={this.state.awayMessage ? ''notLoadedYet'' : ''loaded''} onChange={this.onTextChange} defaultValue={awayMessageText} />

Actualización: dado que esto recibe votos positivos, tendré que decir que debe tener un accesorio disabled o de readonly mientras se carga el contenido, para que no disminuya la experiencia de ux.

Y sí, es muy probable que sea un truco, pero hace el trabajo ... ;-)


Quizás no sea la mejor solución, pero crearía un componente como el siguiente para poder reutilizarlo en cualquier parte de mi código. Desearía que ya estuviera en reaccionar por defecto.

<MagicInput type="text" binding={[this, ''awayMessage.text'']} />

El componente puede verse así:

window.MagicInput = React.createClass onChange: (e) -> state = @props.binding[0].state changeByArray state, @path(), e.target.value @props.binding[0].setState state path: -> @props.binding[1].split(''.'') getValue: -> value = @props.binding[0].state path = @path() i = 0 while i < path.length value = value[path[i]] i++ value render: -> type = if @props.type then @props.type else ''input'' parent_state = @props.binding[0] `<input type={type} onChange={this.onChange} value={this.getValue()} />`

Donde change by array es una función que accede al hash mediante una ruta expresada por un array

changeByArray = (hash, array, newValue, idx) -> idx = if _.isUndefined(idx) then 0 else idx if idx == array.length - 1 hash[array[idx]] = newValue else changeByArray hash[array[idx]], array, newValue, ++idx