我创建了一个React View,例如MyView
,它具有2个文本输入,其初始值将由从数据库读取的父级传递。
我还希望将更改后的值保存回DB。因此,该视图还传递了相同的回调函数。
考虑到数据库保存操作繁重,您不应该经常这样做。因此,我决定在每个按键上调用onBlur
时,在输入框中监听onChange
事件,而不是onChange
事件。
第一种方法:
class MyView extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<input type="url" value={this.props.values.A}
onBlur={(evt)=>{this.props.saveValue('A', evt.target.value)}} />
<input type="url" value={this.props.values.B}
onBlur={(evt)=>{this.props.saveValue('B', evt.target.value)}} />
<button type="button" onClick={this.props.resetValues}>Reset</button>
</div>
);
}
}
但是,这不起作用,因为React
强制执行受控输入(具有value
属性),并始终伴随着onChange
侦听器。
第二种方法:
因此,我尝试将这些输入设为uncontrolled
。也就是说,使用value
代替defaultValue
属性。
<input type="url" defaultValue={this.props.values.A}
onBlur={(evt)=>{this.props.saveValue('A', evt.target.value)}} />
但是,尽管视图被重新渲染,但是defaultValue
在创建视图后不会更新,但是这也不能像单击“重置/清除”按钮那样。
第三种方法:
因此,我终于添加了一个onChange
侦听器,但没有操作。
<input type="url" value={this.props.values.A}
onChange={()=>{console.log('do nothing')}
onBlur={(evt)=>{this.props.saveValue('A', evt.target.value)}} />
同样,由于视图在调用onChange
之后重新呈现,因此该方法不起作用,并且由于值尚未反映在props
中,因此value
似乎在每个键上都重置为初始值中风。
第四种方法:
最后,我尝试维护组件中的state
并从状态读取值,并在每个onChange
上将值保存回状态。这在最大程度上有效,但是只要对道具进行了外部更改并且重新渲染视图,state
就不会更新。因此,我添加了一个getDerivedStateFromProps
函数来查看:
static getDerivedStateFromProps(props, state) {
return props.values;
}
现在,这再次不起作用。原因是即使我临时将值保存到state并将状态在props中重置为初始值,该函数也会被调用。
ReactJS专家可以帮助我解决用例吗?
答案 0 :(得分:1)
您仍然需要onChange
来帮助您设置两个URL输入的状态。 onBlur
仅用于触发保存,它是2个不同的事件,用于不同的目的。
由于您的A和B值是从父级组件向下传递的。 MyView
的父组件应该传递this.state.values
和设置状态的函数。
如果所有内容都在单个组件中,请参考此代码段。您应该可以将handleChange
函数移至其父组件。
class App extends React.Component {
state = {
values: {
A: '',
B: ''
}
}
handleChange = e => {
this.setState({
values: {
...this.state.values,
[e.target.name]: e.target.value
})
}
handleBlur = e => {
if (e.target.name === 'A') {
alert(`Saving A: ${this.state.values.A}`)
}
if (e.target.name === 'B') {
alert(`Saving B: ${this.state.values.B}`)
}
}
render() {
return (
<div>
<label>Value A</label>
<input
type="url"
name="A"
value={this.state.values.B}
onChange={this.handleChange}
onBlur={this.handleBlur}
/>
<label>Value B</label>
<input
type="url"
name="B"
value={this.state.values.A}
onChange={this.handleChange}
onBlur={this.handleBlur}
/>
</div>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('container')
);
<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>
编辑:您的第四种方法应适用于以下情况:
static getDerivedStateFromProps(props, state) {
return { values: props.values }
}
constructor(props) {
super(props)
this.state = {
values: props.values
}
}
所以基本上this.state.values
是真理的最终来源。用户键入内容时,您setState
在此组件中进行更改。但是,如果props.values
(从外部来源)发生更改,则getDerivedStateFromProps
将更新值状态。
答案 1 :(得分:1)
根据对Yeren Yeo解决方案的评论,我将处理componentDidUpdate
上的道具状态和解,在这里您会得到旧的state
和props
。这样,您可以确定this.props
的更新方式并采取相应的措施。当props
中的值与state
或oldProps
不匹配时,更新是外部的,您应该覆盖状态中未保存的更改。
代码应如下所示
componentDidUpdate(prevProps) {
if (this.props.values !== prevProps.values && this.props.values !== this.state.values) {
this.setState({values:this.props.values});
}
}
如果您走这条路线,也可以保留输入uncontrolled
并通过引用更新其值。这解决了controlled
输入的某些不可靠性,例如,当您键入十进制逗号时,type='number'
返回undefined
作为其值。您仍然需要存储值onChange
,但只保存它onBlur
并在componentDidUpdate
中处理状态专有对帐
答案 2 :(得分:0)
因此,基于onChange起作用的想法,我建议您看一下:
https://schier.co/blog/2014/12/08/wait-for-user-to-stop-typing-using-javascript.html 导航至标题:等待键入停止
希望它可以使您达到想要的目标。