你其实不必为React表单受控还是非受控而纠结

这两天在浏览 React 官方文档关于非受控组件部分时,官方推荐了一篇文章: Controlled and uncontrolled form inputs in React don’t have to be complicated。写的简洁清晰,所以想着做一次翻译练习,同时希望能给还在为控还是不控而纠结的朋友们提供一点参考。

在这里插入图片描述
你也许读过很多文章中说: "我们应该避免使用 setState ",但是几乎又有同样数量的文章却说: “使用 ref 是很糟糕的”。。。这可是两种矛盾的用法,相当于一方说要用非受控组件,一方却又说当然是受控组件好。对于初学者来说,遇到这种情况很难作出选择,也很难了解清楚选择的准则应该是什么。

终极问题就是:我应该如何开发一个 Fom 组件 ?

可以说,Form 是大多数 web 应用的核心组件。因此对 Form 表单的处理也成为了 React 的核心功能之一。

但是无需担心,接下来我会讲解 Form 表单中的受控 (Controlled) 以及非受控 (Uncontrolled)组件,以及对应的使用场景。

非受控组件 (The Uncontrolled)

非受控组件的使用方式就像我们操纵原生 html 组件。通过 DOM 来获取控件的 value。
我们以实现一个简单的 Form 组件为例:

class Form extends Component {
  render() {
    return (
      <div>
        <input type="text" />
      </div>
    );
  }
}

你可以通过 ref 来获取控件的 value。我们在上面的组件中再增加一个 button 控件,点击 button 获取 input 控件的 value 值。

class Form extends Component {
  handleSubmitClick = () => {
    const name = this._name.value;
    // do something with `name`
  }

  render() {
    return (
      <div>
        <input type="text" ref={input => this._name = input} />
        <button onClick={this.handleSubmitClick}>Sign up</button>
      </div>
    );
  }
}

由上可见,我们从 input 控件获取值的方式类似于拉取(pull)。这个操作通常发生在我们提交表单的时候。

上面的例子是在 React 中实现 Form 表单最简单的一种方式,这也正好说明了非受控组件的适用场景:当业务逻辑非常简单的时候,还有一种场景估计就是你还是个 React 新手的时候。。

受控组件 (The Controlled)

一个受控组件 (controlled input) 以 props 的方式接收当前值,对于值发生改变时的回调函数也遵循同样的方式。这种使用方式很 “React” (但这并不意味着我们在开发种必须使用这种方式)

<input value={someValue} onChange={handleChange} />

在 React 中,作为 props 传递的控件的值通常存放在其所在 Component 的 state 中。

class Form extends Component {
  constructor() {
    super();
    this.state = {
      name: '',
    };
  }

  handleNameChange = (event) => {
    this.setState({ name: event.target.value });
  };

  render() {
    return (
      <div>
        <input
          type="text"
          value={this.state.name}
          onChange={this.handleNameChange}
        />
      </div>
    );
  }
}

当然,存放在其所在 Component 中的 state 不是绝对的,props 的传值可以来在于其他 Component 甚至是单独的 state store 比如 Redux

每当用户输入一个新的字符,handleNameChange 会被调用,它会将当前 input 的值更新到 Component 的 state 中。

在这里插入图片描述

  • input 初始状态值为空字符串 ‘’
  • 用户键入一个 ‘a’ , handleNameChange回调函数取得该值同时 setState 触发一次渲染将用户键入的值展示在屏幕上
  • 用户继续输入 ‘b’, handleNameChange回调函数取得值 ‘ab’ 同时 setState 触发一次渲染将用户键入的值展示在屏幕上即 value = ‘ab’

上述过程像是将控件由于 onChange 而产生的新值推送(push)给 Form Component,因此 Form 总是可以获得控件的最新值。

数据 (state) 和 UI (inputs) 总是保持同步状态。input 中的值从 state 获取,input 通过回调向 Form 发起请求更新 state。

我们可以看出,Form Component 对控件 onChange 的反应是实时的,可适用于如下场景:

  • 即时反馈:表单输入验证 (validation)
  • 在所有字段验证通过前,将提交 button 置灰 disabled
  • 控件对输入格式有要求,比如信用卡号,身份证号等。

如果你的业务逻辑简单到根本没有上述场景,那么使用非受控组件可能是个更好的选择。

组件受控的本质

除了上述举例的 input 控件,Form 表单还有其他控件比如 checkbox, radio, select 和 textarea.

Form 表单中控件的 value 值,是通过 props 绑定获取,那么我们就称控件是受控的。就这么简单!

不同的 Form 表单控件,有不同的 value 形式,如下表所示:
在这里插入图片描述

总结

受控组件与非受控组件各有优点。我们应该根据自身业务逻辑的特点与场景综合评估来做出选择,适合自己的就是好的。

如果我们业务中用到的表单逻辑交互非常简单(very simple),那么使用非受控组件 (ref方式) 就足够用了。你不必在意很多文章中所说的使用 ref 是多么的 "不好"

在这里插入图片描述
当然,以上建议并不是一锤子买卖,任何非受控组件都可以写成受控组件的形式:Going from uncontrolled to controlled inputs is not hard

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值