React input defaultValue doesn't update with state

我试图创建一个简单的带有 response 的表单,但是很难将数据正确地绑定到表单的 default Value。

我要找的行为是这样的:

  1. 当我打开我的页面时,文本输入字段应该用我的 AwayMessage 在我的数据库中的文本填充。这是“样本文本”
  2. 理想情况下,如果我的数据库中的 AwayMessage 没有文本,那么我希望在 Text 输入字段中有一个占位符。

但是,现在,我发现每次刷新页面时,Text 输入字段都是空白的。(尽管我在输入中输入的内容可以正确保存并保持。)我认为这是因为输入文本字段的 html 在 AwayMessage 是空对象时加载,但是在 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>

my console.log for AwayMessage shows the following:

AWAY_MESSAGE Object {}
AWAY_MESSAGE Object {id: 1, company_id: 1, text: "Sample Text", master_toggle: false}
109672 次浏览

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

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

数组变化是一个函数访问哈希通过一个数组表示的路径

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

DefaultValue 仅用于初始加载

如果您想初始化输入,那么您应该使用 defaultValue,但是如果您想使用 state 来更改值,那么您需要使用 value。就个人而言,如果我只是初始化 defaultValue,那么我喜欢使用 defaultValue,然后在提交时使用 refs 来获取值。有更多关于参考文献和反应文档输入的信息,https://facebook.github.io/react/docs/forms.htmlhttps://facebook.github.io/react/docs/working-with-the-browser.html

我会这样重写你的输入:

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

而且你也不想传递占位符文本,因为这样会将值设置为‘占位符文本’。您仍然需要向输入传递一个空值,因为 unDefinition 和 nil 实际上将 value 转换为 defaultValue。https://facebook.github.io/react/tips/controlled-input-null-value.html.

GetInitialState 不能调用 api

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

我还推荐阅读使用 response 的组件生命周期。

通过修改和加载状态重写

就个人而言,我不喜欢做整个如果否则,然后在渲染逻辑,宁愿使用’加载’在我的状态,并呈现一个字体可怕的微调器之前的形式加载,http://fortawesome.github.io/Font-Awesome/examples/。这里有一个重写,告诉你我的意思。如果我搞错了 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>

差不多够了。这是使用状态和值的表单的一种方法。您也可以使用 defaultValue 代替 value,然后在提交时使用 refs 获取值。如果您采用这种方法,我建议您使用一个外层 shell 组件(通常称为高阶组件)来获取数据,然后将其作为道具传递给表单。

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

另一种解决方法是改变输入的 key

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

更新: 由于这会得到更多的赞同,我不得不说,当内容加载时,您应该正确地使用 disabledreadonly道具,这样就不会降低用户体验。

And yea, it is most likely a hack, but it gets the job done.. ;-)

Give value to parameter "placeHolder". 例如:-

 <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}
/>

相关问题

在控制上设置 defaulValue不会不更新 state

逆向操作非常有效:

  • state设置为默认值,控件 UI 将正确更新,就像给定了 defaulValue一样。

Code:

let defaultRole = "Owner";


const [role, setRole] = useState(defaultRole);


useEffect(() => {
setMsg(role);
});


const handleChange = (event) => {
setRole(event.target.value );
};


// ----


<TextField
label="Enter Role"
onChange={handleChange}
autoFocus
value={role}
/>

要强制 defaultValue 重新呈现,您需要做的只是更改输入本身的键值。你要这么做。

<input
type="text"
key={myDynamicKey}
defaultValue={myDynamicDefaultValue}
placeholder="It works"/>
  1. 为默认值定义一个状态
  2. divkey道具包围你的输入
  3. 将键值设置为与输入的 defaultValue 相同的值。
  4. 调用在步骤1中定义的 setDefaultValue以重新呈现组件

例如:

const [defaultValue, setDefaultValue] = useState(initialValue);


useEffect(() => {
setDefaultValue(initialValue);
}, false)


return (
<div key={defaultValue}>
<input defaultValue={defaultValue} />
</div>
)

使用 value而不是 defaultValue,并使用 onChange方法更改输入的值。

it's extremely simple, make defaultValue and key the same:

<input defaultValue={myVal} key={myVal}/>