# react 的 非受控组件 和 受控组件

98 阅读5分钟

react 的 非受控组件 和 受控组件

组件分为 非受控组件 和 受控组件,这两种有什么区别呢,单说概念不好理解,那我们通过一个案例来说明一下,一下子就可以弄懂了,很简单的。

案例

还是,以案例的方式开头,在实现案例的同时说明一下两个类型的组件。

我们做一个表单,点击表单提交参数对吧。

在这里插入图片描述 好,我们就做上面效果图一样的案例。

非受控组件

首先我们先写一个表单吧。我这边直接写代码了,一些具体的写法就不细说了,看不懂的直接翻我以前的博客,都有讲解。

   <!-- 此处必须写 text/babel -->
    <script type="text/babel">
        // 创建组件
        class Login extends React.Component {
        
            render() {
                return (
                    <form action="http://www.baidu.com">
                        账号:<input type="text" name="username" /> <br />
                        密码:<input type="password" name="password" /><br />
                        <button>登 录</button>
                    </form>
                )
            }
            
        }
        // 渲染组件
        ReactDOM.render(<Login />, document.getElementById("app"))
    </script>

上面的代码我相信都可以看懂是吧?写了一个单纯的表单,点击按钮他会把我们的账号密码带到百度去,我们保存刷新看一下效果先。

在这里插入图片描述 OK,到这里都是没有问题的吧。

但是有点瑕疵啊,就是我们在做项目的时候呢,一般是 ajax 请求,我们的页面不能刷新,包括地址,页面都是不能动的,显然写到这里有瑕疵,不对,所以我们需要修改一下。

怎么修改呢,有人说不想跳转页面就把 form 表单的 action 删掉就可以了嘛! 我们试一下哈。

            render() {
                return (
                    <form>
                        账号:<input type="text" name="username" /> <br />
                        密码:<input type="password" name="password" /><br />
                        <button>登 录</button>
                    </form>
                )
            }

代码我们已经把 form 表单的 action 去掉了,我们在操作一遍看一下效果:

在这里插入图片描述 我们看到哈,action 删除掉之后,点击按钮之后,页面确实不跳转了,但是呢,地址变了对吧?

这不行,地址变得原因是因为啥呢,就是 form 表单默认操作的,我们不想让地址变的话,取消掉 form 的默认提交方式,我们自己写弹窗信息就可以了吧。

form 表单默认提交的方式是 onsubmit 方法,我们重新设置一下,当然了, react 中使用不能写 onsubmit,而是改为了 onSubmit,切记。我们修改代码,首先取消掉他的默认事件,我们不用了,然后自己写一个事件先取消掉 form 的默认事件。

    <!-- 此处必须写 text/babel -->
    <script type="text/babel">
    
        // 创建组件
        class Login extends React.Component {

            handleSubmit = (event) => {
                event.preventDefault()  // 阻止默认事件,即表单提交组织
            }
            
            render() {
                return (
                    <form action="http://www.baidu.com" onSubmit={this.handleSubmit}>
                        账号:<input type="text" name="username" /> <br />
                        密码:<input type="passwofd" name="password" /><br />
                        <button>登 录</button>
                    </form>
                )
            }
        }
        // 渲染组件
        ReactDOM.render(<Login />, document.getElementById("app"))
    </script>

OK,我们在 handleSubmit 中取消了他的默认事件,这样就不会在点击按钮的时候自动跳转和修改路径了。

在这里插入图片描述 我们可以看到,点击按钮的时候已经不会再跳转也不会修改我们路径了哈。

接下来就是弹窗展示数据了。

上一篇博客说了要尽可能的减少使用 refs ,通过事件源获得数据,这个地方可以用吗?

显然是不可以的吧?因为我们操作的 dom 是按钮,但是我们在 按钮的点击事件里面想要获取的是两个 input 输入框的值,显然是不可以的,所以说还是得用 refs。

那这个就很简单了,不详细说了。

    <!-- 此处必须写 text/babel -->
    <script type="text/babel">
    
        // 创建组件
        class Login extends React.Component {

            handleSubmit = (event) => {
                event.preventDefault()  // 阻止默认事件,即表单提交组织
                const { username, password } = this
                alert(`你输入的账号是 ${username.value},你输入的密码是 ${password.value}`)
            }


            render() {
                return (
                    <form action="http://www.baidu.com" onSubmit={this.handleSubmit}>
                        账号:<input ref={c => this.username = c} type="text" name="username" /> <br />
                        密码:<input ref={c => this.password = c} type="passwofd" name="password" /><br />
                        <button>登 录</button>
                    </form>
                )
            }
        }
        // 渲染组件
        ReactDOM.render(<Login />, document.getElementById("app"))
    </script>

保存,看一下效果。

在这里插入图片描述

OK,案例的要求就写完了,效果一模一样对吧!

上边我们写的组件,就是 非受控组件。很多宝子懵了吧?为啥啊?为啥他就是非受控组件啊!

非受控组件的特点就是 现用现取 啊!

啥是现用现取,你看上边我们写的代码,我们点击按钮需要显示弹窗展示数据吧?我们在点击弹窗的时候才去获取的账号和密码,是用的时候现取的数据吧?这就是现用现取,只要是现用现取,就是非受控组件。

好,非受控组件就到这里。

【该部分相关代码资料】:我是𝒆𝒅. 的 gitee

受控组件

上面我们说了 非受控组件,很多人可能不是很理解,觉得这是很正常的逻辑啊,没关系,我们现在说一下受控组件,说完受控组件,就会有一种恍然大明白的感觉。

我们还是上边的案例。

我们知道 input 输入框是不是有一个 onchange 事件啊!就是当我们 input 输入框的内容改变后就会触发,当然,react 里面要 onChange 这样写,我们试一下。

            saveUsername = (event) => {
                console.log(event.target.value)
            }

            render() {
                return (
                    <form action="http://www.baidu.com" onSubmit={this.handleSubmit}>
                        账号:<input onChange={this.saveUsername} type="text" name="username" /> <br />
                        密码:<input ref={c => this.password = c} type="passwofd" name="password" /><br />
                        <button>登 录</button>
                    </form>
                )
            }

我们打印一下 账号输入框改变的数据:

在这里插入图片描述 OK,效果是可以的哈。

那我们做这样一件事。

当我们每当账号、密码内容改变的时候,我们都把改变后的数据放到状态 state 当中保存起来,点击的时候,就可以直接从 状态 里面获取展示弹窗。没问题吧!

修改一下代码:

	<!-- 此处必须写 text/babel -->
    <script type="text/babel">
        
        // 创建组件
        class Login extends React.Component {

			// 首先初始化状态,严禁不初始化状态直接使用
            state = { username: '', password: '' }

            handleSubmit = (event) => {
                event.preventDefault()  // 阻止默认事件,即表单提交组织
                
                const { username, password } = this.state  // 从 state 种获取数据
                
                alert(`你输入的账号是 ${username},你输入的密码是 ${password}`)
            }

            saveUsername = (event) => {
                // console.log(event.target.value)
                this.setState({ username: event.target.value }) // 把账号的数据值存到状态
            }

            savePassword = (event) => {
                // console.log(event.target.value)
                this.setState({ password: event.target.value }) // 把密码的数据值存到状态
            }


            render() {
                return (
                    <form action="http://www.baidu.com" onSubmit={this.handleSubmit}>
                        账号:<input onChange={this.saveUsername} type="text" name="username" /> <br />
                        密码:<input onChange={this.savePassword} type="passwofd" name="password" /><br />
                        <button>登 录</button>
                    </form>
                )
            }
        }
        // 渲染组件
        ReactDOM.render(<Login />, document.getElementById("app"))
    </script>

看上面代码,都懂是吧?仔细看哈,我们存到状态里面的直接就是 数据值,不是 dom 节点,所以说展示弹窗的时候直接取值就可以了,不需要在 .value。保存刷新查看效果:

在这里插入图片描述 OK。效果也实现了,这个代码写的组件,就是受控组件。我们把数据在改变的时候就保存到 state 种,用的时候不是从 input 里面现取的,所以是 受控组件。

对比两个类型的组件。应该理解两者的区别了吧!

好的今天就到这儿,晚安了宝子们~

【本部分关键代码资料】:我是𝒆𝒅. 的 gitee

在这里插入图片描述