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>

你可能感兴趣的:(React,学习实战笔记,react.js,javascript,前端,前端框架)