ReactJS:在模糊而不是每次击键时保存输入值
ReactJS: Save input value on blur and not on every key stroke
我创建了一个 React 视图,比如 MyView
,它有 2 个文本输入,其初始值将由父级从数据库读取传递。
我还想将更改后的值保存回数据库。因此,视图也传递了一个回调函数。
考虑到数据库保存操作繁重,不宜频繁进行。因此,我决定在输入框上监听 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)}} />
但这也没有像 reset/clear 按钮单击时那样工作,虽然视图被重新渲染但是 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;
}
现在,这又没用了。原因是即使我暂时将值保存到状态并且状态被重置为道具中的初始值,也会调用此函数。
一些 ReactJS 专家可以帮助我处理我的用例吗?
您仍然需要 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
将更新值状态。
所以有了 onChange 的想法,我建议你看看这个:
https://schier.co/blog/2014/12/08/wait-for-user-to-stop-typing-using-javascript.html
导航至标题:等待键入停止
希望它能以某种方式引导您实现您想要的目标。
根据对 Liren Yeo 解决方案的评论,我会在 componentDidUpdate
上处理 props-state 协调,在那里你可以得到旧的 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
中处理 state-prop-dom 协调
我创建了一个 React 视图,比如 MyView
,它有 2 个文本输入,其初始值将由父级从数据库读取传递。
我还想将更改后的值保存回数据库。因此,视图也传递了一个回调函数。
考虑到数据库保存操作繁重,不宜频繁进行。因此,我决定在输入框上监听 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)}} />
但这也没有像 reset/clear 按钮单击时那样工作,虽然视图被重新渲染但是 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;
}
现在,这又没用了。原因是即使我暂时将值保存到状态并且状态被重置为道具中的初始值,也会调用此函数。
一些 ReactJS 专家可以帮助我处理我的用例吗?
您仍然需要 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
将更新值状态。
所以有了 onChange 的想法,我建议你看看这个:
https://schier.co/blog/2014/12/08/wait-for-user-to-stop-typing-using-javascript.html 导航至标题:等待键入停止
希望它能以某种方式引导您实现您想要的目标。
根据对 Liren Yeo 解决方案的评论,我会在 componentDidUpdate
上处理 props-state 协调,在那里你可以得到旧的 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