背景

React内部分别使用了props, state来区分组件的属性和状态。props用来定义组件外部传进来的属性, 属于那种经过外部定义之后, 组件内部就无法改变。而state维持组件内部的状态更新和变化, 组件渲染出来后响应用户的一些操作,更新组件的一些状态。如果组件内部状态不需要更新,即没有调用过this.setState, 全部通过props来渲染也是没问题的, 不过这种情况不常见。本文所介绍的内容就是通过props和state的定义来谈谈React的受控组件和非受控组件。

非受控组件

顾名思义, 非受控组件即组件的状态改变不受控制.接来下我们以一个简单input组件代码来描述。

import React, { Component } from 'react';
import ReactDOM from 'react-dom'; class Demo1 extends Component {
render() {
return (
<input />
)
}
} ReactDOM.render(<Demo1/>, document.getElementById('content'))

在这个最简单的输入框组件里,我们并没有干涉input中的value展示,即用户输入的内容都会展示在上面。如果我们通过props给组件设置一个初始默认值,<input defaultValue={this.props.value}/>defaultValue属性是React内部实现的一个属性,目的类似于input的placeholder属性。

ps: 此处如果使用value代替defaultValue,会发现输入框的值无法改变。

受控组件

上面提到过,既然通过设置input的value属性, 无法改变输入框值,那么我们把它和state结合在一起,再绑定onChange事件,实时更新value值就行了。

class Demo1 extends Component {
constructor(props) {
super(props);
this.state = {
value: props.value
}
} handleChange(e) {
this.setState({
value: e.target.value
})
} render() {
return (
<input value={this.state.value} onChange={e => this.handleChange(e)}/>
)
}
}

这就是最简单的受控组件模型, 我们可以通过在onChange的回调里控制input要显示的值,例如我们设置input框只能输入数字

this.setState({
value: e.target.value.replace(/\D/g, '')
})

现在我们应该完全明白form表单中受控组件和非受控组件的关系。受控组件采取的理念类似于redux的单项数据流理念,即value值是在调用者上更新的。

那么问题来了。。。

最后的思考

现在我们要实现一个简单的input的number类型组件,后面紧跟一个+的button按钮,将输入框内的数字每次加一。所以此处只能按照受控组件的理念来写

import React, { Component } from 'react';

export default class extends Component {
constructor(props) {
super(props);
this.state = {
value: props.value
}
} handleChange(e) {
this.setState({
value: e.target.value.replace(/\D/g, '')
})
} plus() {
const value = ++this.input.value
this.setState({
value,
})
} render() {
return (
<div>
<input
value={this.state.value}
onChange={e => this.handleChange(e)}
ref={ref => this.input = ref}
/>
<button onClick={() => this.plus()}>+</button>
</div>
)
}
}

此处功能基本实现完全,但是发现使用此组件之后,面临了另一个问题,我们如何在外部获取到这个输入框的值。一种方法是给组件增加个getValue回调的props,每次value值变化都调用一次getValue,即在handleChange和plus函数里调用,但是存在一个问题是,调用者只能通过getValue被动获取值,而且value值得改变此时还是在组件内部自行变化,不符合受控组件原理,也不满足React单向数据流概念。另一种方法就是将input组件的将要改变的值传到调用者里面,由调用者来决定更不更新组件的值,即此时数据由被调用者input组件生成,传至调用者,调用者判断满足条件后决定更新,再将数据重新传入到被调用者里。而调用者与被调用者彼此之间建立的联系方式通过input组件的props和调用者的state。此时input组件的代码如下

export default class extends Component {
constructor(props) {
super(props);
this.state = {
value: props.value
}
} componentWillReceiveProps(nextProps) {
this.setState({
value: nextProps.value
})
} handleChange(e) {
this.props.onChange(e.target.value)
} plus() {
const value = ++this.input.value
this.props.onChange(value)
} render() {
return (
<div>
<input
value={this.state.value}
onChange={e => this.handleChange(e)}
ref={ref => this.input = ref}
/>
<button onClick={() => this.plus()}>+</button>
</div>
)
}
}

代码中的this.props.onChange就是调用者内部的函数,通过setState来更新input组件的value值。完整代码已放到github,欢迎指正交流。

浅谈React受控与非受控组件的更多相关文章

  1. 七天接手react项目 —— 生命周期&受控和非受控组件&Dom 元素&Diffing 算法

    生命周期&受控和非受控组件&Dom 元素&Diffing 算法 生命周期 首先回忆一下 vue 中的生命周期: vue 对外提供了生命周期的钩子函数,允许我们在 vue 的各个 ...

  2. Vue 中的受控与非受控组件

    Vue 中的受控与非受控组件 熟悉 React 的开发者应该对"受控组件"的概念并不陌生,实际上对于任何组件化开发框架而言,都可以实现所谓的受控与非受控,Vue 当然也不例外.并且 ...

  3. 浅谈React

    浅谈react react是什么?其官网给出了明确定义:A JavaScript library for building user interfaces,一个用于构建用户界面的JavaScript库 ...

  4. 【转】浅谈React、Flux 与 Redux

    本文转自<浅谈React.Flux 与 Redux>,转载请注明出处. React React 是一个 View 层的框架,用来渲染视图,它主要做几件事情: 组件化 利用 props 形成 ...

  5. 浅谈React工作原理

    浅谈React工作原理:https://www.cnblogs.com/yikuu/p/9660932.html 转自:https://cloud.tencent.com/info/63f656e0b ...

  6. 浅谈react受控组件与非受控组件

    引言 最近在使用蚂蚁金服出品的一条基于react的ant-design UI组件时遇到一个问题,编辑页面时input输入框会展示保存前的数据,但是是用defaultValue就是不起作用,输入框始终为 ...

  7. React学习之受控和非受控组件

    受控组件是通过事件完成对元素value的控制,反之就是非受控组件. 1.受控组件的value通过onChange事件来改变,非受控不需要通过事件来改变value. 2.受控组件通过事件通过setSta ...

  8. react 表单受控和非受控

    参见:https://goshakkk.name/controlled-vs-uncontrolled-inputs-react/ 非受控: onSubmit = ()=>{ const val ...

  9. 浅谈React数据流管理

    引言:为什么数据流管理如此重要?react的核心思想就是:UI=render(data),data就是我们说的数据流,render是react提供的纯函数,所以用户界面的展示完全取决于数据层.这篇文章 ...

随机推荐

  1. Apache MPM winnt

    Win32DisableAcceptEx 指令在 apache2.4 被 AcceptFilter None 取代

  2. Sass for循环中编译%时报错解决方案

    sass功能强大,特别是支持for循环,节省大量开发时间,但是在开发时遇到一个问题,直接使用%时没有问题,当有变量时再加% 单位在编译时报错: 这样没有问题: @for $width from 0 t ...

  3. c和c++关于const的一些区别

    以下参考了网上的一些资料并通过程序验证. 注意,以下情况都是用gcc和g++编译器得到的结果,用vs编译器又会有所不同. 以下说下c和c++中const定义的常量的一些区别: c++中用const定义 ...

  4. SNF开发平台WinForm之十二-发送手机短信功能调用-金笛-SNF快速开发平台3.3-Spring.Net.Framework

    1.调用前组装参数 2.调用发送信息服务脚本   .调用前组装参数: BaseSendTaskEntity entity = new BaseSendTaskEntity(); entity.Mess ...

  5. MyBatis知多少(14)分散的数据库系统

    任何一个重要的数据库无疑都会拥有不止一个依赖者.即使该数据库只是简单地被两个Web 应用程序所共享,也有许多事情需要考虑.假设有一个名为网上购物车的Web应用程序,它使用了一个包含类别代码的数据库.就 ...

  6. 关于导出Excel

    Asp.Net 在刚毕业那会,做项目全是服务器控件.导出Excel的代码也很简单,在button触发后台事件后,后台生成一个excel文件,然后读取成字节,输出到客户端. Response.AddHe ...

  7. CentOS下Tmux安装和使用

    Tmux介绍: Tmux是BSD实现的Screen替代品,相对于Screen,它更加先进:支持屏幕切分,而且具备丰富的命令行参数,使其可以灵活.动态的进行各种布局和操作.它可以做到一条命令就启动起来( ...

  8. 游戏开发工具之纹理打包器-3.使用GDI+绘图

    上一次我们实现了把我们要的图片添加到CTreeCtrl控件里去,并显示图片的缩略图,现在开始我们要讲比较重要的部分--绘图区.为了实现能编辑图片的功能,绘图区应该具有如下功能. 1.  添加删除图片. ...

  9. 【解决方案】HTTP could not register URL http://+:6001/

    Failed to host the DeployerNotificationReceiverSystem.ServiceModel.AddressAccessDeniedException: HTT ...

  10. MongoDB的学习--文档的查询

    继续关于<MongoDB权威指南>记录,今天的内容是文档的查询~~ MongoDB官网地址:http://www.mongodb.org/ 我使用的是MongoDB 2.4.8 find函 ...