ReactJS:将输入值保存为模糊而不是每次击键时

时间:2018-11-26 10:55:33

标签: javascript reactjs onblur react-props getderivedstatefromprops

我创建了一个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专家可以帮助我解决用例吗?

3 个答案:

答案 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上的道具状态和解,在这里您会得到旧的stateprops。这样,您可以确定this.props的更新方式并采取相应的措施。当props中的值与stateoldProps不匹配时,更新是外部的,您应该覆盖状态中未保存的更改。

代码应如下所示

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 导航至标题:等待键入停止

希望它可以使您达到想要的目标。