React 奇技淫巧 - defaultValue 和假造 dom diff 算法完成表单重置

我们晓得 React 的规范形式是单向数据流,而其表单项平常须要监听 onChange 事宜,然后经由过程转变外部的 value 往返写表单项的 value,比如以下 input

class App extends React.Component {
  constructor( props ) {
    super( props );
    this.state = {
      inputValue: 'default'
    }

    this.inputChangeHandler = ( e )=>{
      this.setState( {
        inputValue: e.target.value
      } );
    }
  }
  render() {
    return (
      <div>
        <form>
          <input
            value={ this.state.inputValue }
            onChange={ this.inputChangeHandler }
          />
        </form>
      </div>
    )
  }
}

假如表单有许多表单项,那末这类规范的做法须要你写许多个 state 的属性和许多个 onChange 监听函数,这是一个膂力活儿。然则平常的表单运用实在不须要及时监控表单项的用户输入,用 defaultValue 足以,在表单项目 onBlur 或许末了提交的时刻一次考证猎取用户输入即可,比如:

class App extends React.Component {
  constructor( props ) {
    super( props );

    this.submit = ( e )=>{
      let userInputValue = this.refs.userInput.value;
      // 1. 考证 userInputValue
      // 2. 提交表单
    }
  }
  render() {
    return (
      <div>
        <form>
          <input 
            ref="userInput"
            defaultValue="default"
          />
          <button onClick={ this.submit }>提交</button>
        </form>
      </div>
    )
  }
}

如许就可以够少写不少代码,固然你能够写一些东西去批量增加一切的 onChange 事宜监听函数和对应的 state 的属性,比如 redux-form。(转头一想,这类写法在提交时刻也须要写许多猎取用户输入的代码,假如运用第一种正形式,那末提交时刻只须要猎取 state 就可以够了,不过这里先不议论这些)<br/>
关于一个表单而言,平常还须要重置功用(reset),假如是第一种正形式的写法,我们只需保留一份初始化的默认值,在用户点击到了重置后,经由过程 setState 设归去就好了。然则假如运用第二种 defaultValue 的写法,那末就没有办法了,由于 defaultValue 只在第一次建立假造 dom 的时刻有作用,假如 dom 不转变你转变 defaultValue 是没有效的。这个时刻该怎么办呢?<br/>
嘿嘿!这个时刻我们就可以够用到这个奇技淫巧了。既然 defaultValue 是在建立假造 dom 的时刻有效,那末我们在用户点击重置的时刻让 React 从新建立这些表单项的假造 dom 不就好了么。依据 React 假造 dom diff 的算法,只需转变 dom 节点的范例就可以促使在 diff 的时刻从新建立假造 dom。详细的写法我们就用代码来演示下:

class App extends React.Component {
  constructor( props ) {
    super( props );
    // fieldSetWrapperType 是一个标志位属性,render 中会依据这个变量的值的差别,衬着差别的元素
    this.fieldSetWrapperType = 'div';
    this.submit = ( e )=>{
      let userInputValue = this.refs.userInput.value;
      // 1. 考证 userInputValue
      // 2. 提交表单
    }
    this.reset = ()=>{
      // 点击重置,转变标志位
      this.fieldSetWrapperType = this.fieldSetWrapperType === 'div' ? 'section' : 'div';
      // 强迫革新这个组件
      this.forceUpdate();
    }
  }
  // 把表单项的衬着笼统到一个要领中,防止反复编码
  renderFieldSet() {
    return (
      <input 
        ref="userInput"
        defaultValue="default"
      />
    );
  }
  render() {
    return (
      <div>
        <form>
          {
          /* 依据 fieldSetWrapperType 值的差别,衬着差别的元素(表单项的 wrapper 元素) */
          this.fieldSetWrapperType === 'div' ? 
          <div className="wrapper">{ this.renderFieldSet() }</div>
          :
          <section className="wrapper">{ this.renderFieldSet() }</section>
          }
          <button onClick={ this.submit }>提交</button>
          <button onClick={ this.reset }>重置</button>
        </form>
      </div>
    )
  }
}

思绪就是在表单项外面包一层元素,每次点击重置后转变一个变量,再强迫革新这个组件,组件依据这个变量差别的值把这个包装元素的 type 转变,那末它下面的一切表单项的假造 dom 都会被从新建立,达到了重置的目标。不过这个结果依赖于 React 假造dom diff 算法。假如今后算法转变了,那末能够就失效了,而且这个写法是反形式的,我初志是想在处置惩罚巨型表单时刻少写点代码偷懒用。假如运用时刻涌现什么副作用,鄙人概不负责。

此技能在写文章时 React 正处于 15.4.x 的版本

    原文作者:Bernie维尼
    原文地址: https://segmentfault.com/a/1190000009481844
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞