我创建了一个React View,比如MyView
,它有两个文本输入,其初始值将由从DB读取的父级传递。
我还希望将更改后的值保存回DB。因此,视图也被传递了一个相同的回调函数。
请考虑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
。也就是说,使用了defaultValue
而不是value
属性。
<input type="url" defaultValue={this.props.values.A}
onBlur={(evt)=>{this.props.saveValue('A', evt.target.value)}} />
但这也不能像单击重置/清除按钮一样工作,尽管视图是为了重新渲染,但defaultValue
在创建视图后不会更新。
第三种方法:
因此,我最终添加了一个onChange
侦听器,但作为no-op。
<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专家能帮我做用例吗?
您仍然需要onChange
来帮助设置两个url输入的状态。onBlur
仅用于触发保存,它是两个不同的事件,用于不同的目的。
自从你的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
}
}
所以基本上CCD_ 25是真理的最终来源。当用户键入某个内容时,您可以在此组件中setState
并对其进行更改。但如果props.values
发生更改(来自外部源(,getDerivedStateFromProps
将更新值状态。
根据对Liren 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
中处理状态道具dom对账
因此,考虑到onChange的有效性,我建议您看看这个:
https://schier.co/blog/2014/12/08/wait-for-user-to-stop-typing-using-javascript.html导航至标题:等待键入停止
希望它能以某种方式引导你实现你想要的目标。