React 入门:受控组件与非受控组件

首先说明,我们基于表单数据的处理方式来理解受控组件与非受控组件。

非受控组件

概念介绍

非受控组件中,表单数据将交由 DOM 节点来处理,类似原生 JS 中获取 DOM 值的思路(document.getElementById("test"))一样,只是在 React 是通过 Refs 来实现。

通俗的讲,对非受控组件而言,表单元素的值,是“随用随取”。

示例代码

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>非受控组件</title>
</head>

<body>
  <!-- 准备好一个容器 -->
  <div id="app"></div>

  <!-- step01: 引入react核心库 -->
  <script type="text/javascript" src="../js/react.development.js"></script>
  <!-- step02: 引入react-dom,用于支持react操作DOM -->
  <script type="text/javascript" src="../js/react-dom.development.js"></script>
  <!-- step03: 引入babel,用于将jsx转为js -->
  <script type="text/javascript" src="../js/babel.min.js"></script>

  <script type="text/babel"> /* 此处一定要写babel */

        // 1. 创建类式组件
        class LoginForm extends React.Component {

            // 创建 ref 容器
            accountInputRef = React.createRef()
            passwordInputmyRef = React.createRef()

            handleSubmit = (event) => {
              event.preventDefault();

              const {accountInputRef, passwordInputmyRef} = this
              console.log('@', `账号:${accountInputRef.current.value},密码:${passwordInputmyRef.current.value}`)
            }

            render() {
                return (
                    <form onSubmit={this.handleSubmit}>
                      <p>账号:<input type="text" ref={this.accountInputRef} /></p>
                      <p>密码:<input type="password" ref={this.passwordInputmyRef} /></p>
                      <button>登录</button>
                    </form>
                )
            }
        }

        // 渲染组件到页面
        ReactDOM.render(<LoginForm />, document.getElementById('app'));
    </script>

</body>

</html>

受控组件

什么是受控组件

受控组件中,表单数据是由 React 组件中的 state 来管理的。也即是说受控组件就是受组件 state 的控制。

受控组件中的表单元素,需要绑定监听表单元素值变化的事件(通常是 onChange 事件),当表单元素的值发生变化时,将变化后的值更新到 state,当需要使用表单元素的值的时候,再通过 state 来取。

受控组件还有个特点,就是不使用 Refs 。

示例代码

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>受控组件</title>
</head>

<body>
  <!-- 准备好一个容器 -->
  <div id="app"></div>

  <!-- step01: 引入react核心库 -->
  <script type="text/javascript" src="../js/react.development.js"></script>
  <!-- step02: 引入react-dom,用于支持react操作DOM -->
  <script type="text/javascript" src="../js/react-dom.development.js"></script>
  <!-- step03: 引入babel,用于将jsx转为js -->
  <script type="text/javascript" src="../js/babel.min.js"></script>

  <script type="text/babel"> /* 此处一定要写babel */

        // 1. 创建类式组件
        class LoginForm extends React.Component {

            // 初始化 state
            state = { account: '', password: ''}

            // 保存账号到 state
            saveAccount = (event) => {
              this.setState({account: event.target.value})
            }

            // 保存密码到 state
            savePassword = (event) => {
              this.setState({password: event.target.value})
            }

            // 表单提交的回调
            handleSubmit = (event) => {
              event.preventDefault();

              const {account, password} = this.state
              console.log('@', `账号:${account},密码:${password}`)
            }

            render() {
                return (
                    <form onSubmit={this.handleSubmit}>
                      <p>账号:<input type="text" onChange={this.saveAccount} /></p>
                      <p>密码:<input type="password" onChange={this.savePassword} /></p>
                      <button>登录</button>
                    </form>
                )
            }
        }

        // 渲染组件到页面
        ReactDOM.render(<LoginForm />, document.getElementById('app'));
    </script>

</body>

</html>

上面的代码比较简单,仅用于示例演示。如果用于实际工作中,就会有问题,比如一个表单可能会有多个表单元素,那我们就需要写很多个 saveXxx 的事件绑定函数,这样写倒是也没错,只是比较麻烦,代码也不好维护。

代码优化

针对上面这个问题,接下来我们通过使用【高阶函数】和【函数的柯里化】对其进行优化来解决上面的问题。
先科普两个概念:

  • 什么是高阶函数

    如果一个函数符合下面 2 个规范中的任何一个,那该函数就是高阶函数。

    • 若 A 函数,接收的参数是一个函数,那 A 就称之为高阶函数。
    • 若 A 函数,调用的返回值依然是一个函数,那 A 就称之为高阶函数。

常见的高阶函数:Promise,setTimeout,arr.map()等。

  • 什么是函数柯里化

    通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式。

处理后的代码如下:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>使用高阶函数和函数柯里化优化受控组件</title>
</head>

<body>
  <!-- 准备好一个容器 -->
  <div id="app"></div>

  <!-- step01: 引入react核心库 -->
  <script type="text/javascript" src="../js/react.development.js"></script>
  <!-- step02: 引入react-dom,用于支持react操作DOM -->
  <script type="text/javascript" src="../js/react-dom.development.js"></script>
  <!-- step03: 引入babel,用于将jsx转为js -->
  <script type="text/javascript" src="../js/babel.min.js"></script>

  <script type="text/babel"> /* 此处一定要写babel */

        // 1. 创建类式组件
        class LoginForm extends React.Component {

            // 初始化 state
            state = { account: '', password: ''}

            // 保存表单字段的值到 state,运用了高阶函数和函数的柯里化的技术
            saveFormData = (fieldName) => {
              return (event) => {
                this.setState({[fieldName]: event.target.value})
              }
            }

            // 表单提交的回调
            handleSubmit = (event) => {
              event.preventDefault();

              const {account, password} = this.state
              console.log('@', `账号:${account},密码:${password}`)
            }

            render() {
                return (
                    <form onSubmit={this.handleSubmit}>
                      <p>账号:<input type="text" onChange={this.saveFormData('account')} /></p>
                      <p>密码:<input type="password" onChange={this.saveFormData('password')} /></p>
                      <button>登录</button>
                    </form>
                )
            }
        }

        // 渲染组件到页面
        ReactDOM.render(<LoginForm />, document.getElementById('app'));
    </script>

</body>

</html>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西涯三锋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值