React input defaultValue不会更新状态

我试图创build一个简单的forms与反应,但面临困难的数据正确地绑定到窗体的defaultValue。

我正在寻找的行为是这样的:

  1. 当我打开我的页面时,文本input字段应填入我的数据库中的AwayMessage文本。 这是“示例文本”
  2. 理想情况下,如果我的数据库中的AwayMessage没有文本,我想在文本input字段中有一个占位符。

但是,现在,我发现每次刷新页面时,文本input字段都是空白的。 (虽然我input的input确实保存并保持。)我认为这是因为input文本字段的html加载时,AwayMessage是一个空的对象,但不会刷新时,离开消息加载。 另外,我无法指定该字段的默认值。

我删除了一些清晰的代码(即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> 

我的console.log为AwayMessage显示以下内容:

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

defaultValue仅用于初始加载

如果你想初始化input,那么你应该使用defaultValue,但是如果你想使用状态来改变这个值,那么你需要使用值。 我个人喜欢只使用defaultValue,如果我只是初始化它,然后只是使用refs获取提交时的值。 关于反应文档的参考和input,请参阅https://facebook.github.io/react/docs/forms.html和https://facebook.github.io/react/docs/working-with-the- browser.html 。

以下是我将如何重写您的input:

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

你也不想传递占位符文本,因为它实际上将值设置为“占位符文本”。 您仍然需要将一个空值传入input,因为undefined和nil本质上将值转换为defaultValue。 https://facebook.github.io/react/tips/controlled-input-null-value.html

getInitialState不能进行api调用

getInitialState运行后,您需要进行api调用。 对于你的情况,我会在componentDidMount中做到这一点。 按照这个例子, https://facebook.github.io/react/tips/initial-ajax.html

我还build议阅读元件生命周期的反应。 https://facebook.github.io/react/docs/component-specs.html

用修改和加载状态重写

就我个人而言,我不喜欢在渲染中完成整个if else逻辑,并且喜欢在我的状态下使用“加载”,并在表单加载之前渲染字体真棒微调, http://fortawesome.github.io/Font-真棒/例子/ 。 这里有一个改写,告诉你我的意思。 如果我搞砸了cjsx的蜱虫,那是因为我通常只是使用这样的咖啡脚本。

 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> 

这应该关于它。 现在,这是使用状态和价值的forms的一种方式。 您也可以使用defaultValue而不是value,然后在提交时使用refs来获取值。 如果你走这条路线,我会build议你有一个shell组件(通常被称为高阶组件)来获取数据,然后将其作为道具传递给表单。

总的来说,我build议读完反应文档,并做一些教程。 有很多博客在那里和http://www.egghead.io有一些很好的教程。; 我的网站上也有一些东西, http://www.openmindedinnovations.com

解决这个问题的另一种方法是改变input的key

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

更新:因为这得到upvotes,我不得不说,你应该正确地有一个disabledreadonly prop,而内容加载,所以你不会减lessux的经验。

而且,这很可能是一个黑客,但它完成了工作.. 😉

也许不是最好的解决scheme,但我会做一个像下面的组件,所以我可以在我的代码中的任何地方重用。 我希望它已经在默认情况下反应了。

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

该组件可能如下所示:

 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()} />` 

数组的改变是通过数组expression的path访问哈希的函数

 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 

虽然不build议通过反应,它的工作原理:

 render() { const { value } = this.state; return <input defaultValue={value} value={value} />; } 

你可能会发现很容易摧毁一个元素,并用新的replace它

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

喜欢这个:

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

你也可以使用这个版本的卸载方法:

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