受控组件和非受控组件主要是用来解决表单组件状态谁来控制的问题。因为用户的输入会反应在界面上,相当于视图的状态发生了变化,而react是通过虚拟DOM比对修改视图的,这里就要决定谁来控制表单组件的状态。由用户直接控制的称为非受控组件,而由react的控制的,称为受控组件。

1. 非受控组件

没有设置value/checked的表单组件,表单数据有DOM元素本身处理
组件自己控制组件的状态,一般父组件会给它一个初始值(通过defaultValue属性)
defaultValue/defaultChecked设置默认值,首次生效,重新渲染后则不生效,有value时也不生效
input元素本身也有defaultValue属性,可以设置或返回其默认值
defaultValue需要在constructor或者componentWillMount设置设置state
其他周期中设置的在render后无法看到默认值

形如:

 <input type="text" />

非受控组件与普通input一致,用户的输入正常显示,由用户来控制组件的状态。

非受控组件通常和ref结合在一起,通过node.value方式来获取dom节点的值,这种方式适合不需要知道实时状态,只需要提交的表单组件。

import React, { Component } from 'react';

class UnControlled extends Component {
handleSubmit = (e) => {
console.log(e);
e.preventDefault();
console.log(this.name.value);
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input type="text" ref={i => this.name = i} defaultValue="BeiJing" />
<button type="submit">Submit</button>
</form>
);
}
} export default UnControlled;

非受控组件的父子组件形式:

//父组件
class Parent extends Component {
render() {
return
<NumberInput defaultValue=20 />;
}
} //子组件NumberInput
class NumberInput extends Component {
render() {
return
<input type="text" className="NumberInput"
defaultValue={this.props.defaultValue} /> }
}

2. 受控组件

设置了value/checked的表单组件,其vaule/checked必须是react组件的state,并且有onChange事件来修改state
组件自己不更新值,而是把值传递给父组件,让父组件决定是否更改。

形如:

<input value="this.state.name" onChange="fHandleChange" />

受控组件通常如下:

<input
type="text"
value={this.state.value}
onChange={(e) => {
this.setState({
value: e.target.value.toUpperCase(),
});
}}
/>

1. 可以通过初始state中设置表单的默认值;
2. 每当表单的值发生变化时,调用onChange事件处理器;
3. 事件处理器通过合成事件对象e拿到改变后的状态,并更新应用的state.
4. setState触发视图的重新渲染,完成表单组件值得更新

受控组件不同表单组件的处理形式:

受控组件的说明:

1. 受控组件会频繁触发change事件,会带来一定的性能损耗,但是影响不大,为了状态的统一,值得一做
2. 受控组件要value和onChange事件配合使用,写起来麻烦,有一些简化手段:
  1. 封装一个InputItem组件,将value和change作为参数
  2. 使用一个onChange方法处理多个Input,内部使用switch来分别处理不同组件的状态

受控组件的父子组件形式:

//父组件
class Parent extends Component {
constructor(props) {
super(props);
this.state = {value: 1};
this.onChangeHandle = this.onChange.bind(this);
}
onChange(event) {
//处理值
if (改) {
this.setState({value: event.target.value});
}
}
render() {
return
<NumberInput value={this.state.value} onChange={this.onChangeHandle} />
;
}
}
//子组件NumberInput
class NumberInput extends Component {
constructor(props) {
super(props);
this.state = {
value: props.value
}; this.onChangeHandle = this.onChange.bind(this);
}
//接收到新的属性时更新state
componentWillReceiveProps(nextProps) {
this.setState({
value: nextProps.value
});
}
onChange(event) {
//通知父组件值更新了
this.props.onChange(event);
}
render() {
return
<input type="text" className="NumberInput"
value={this.state.value}
onChange={this.onChangeHandle} />
}
}

3. 混合组件(既支持受控组件也支持非受控组件的组件)

//父组件
//把子组件当受控组件(传递value和onChange):
render() {
return <NumberInput value={this.state.value} onChange={this.onChangeHandle} />
}
//把子组件当非受控组件(传递defalutValue):
render() {
return <NumberInput defaultValue={this.state.value} />
} //子组件NumberInput
class NumberInput extends Component {
constructor(props) {
super(props);
this.state = {
value: props.value
};
this.onChangeHandle = this.onChange.bind(this);
}
//接收到新的属性时更新state
componentWillReceiveProps(nextProps) {
this.setState({
value: nextProps.value
});
}
onChange(event) {
//通知父组件值更新了
this.props.onChange(event);
}
render() {
let val = {};
//判断组件的props属性是否有value属性,有的话,是受控组件,没有的话是非受控组件
this.props['value'] === undefined ?
(val = {'defaultValue': this.props.defaultValue}) :
(val = {'value': this.state.value});
//使用对象和分解运算符来完成不同属性的切换
return <input type="text" className="NumberInput"
{...val}
onChange={this.onChangeHandle} />;
}
}

混合组件的基本原则:

1. props.value总是有比内部state.value跟高的优先级
2. 组件中所有的变化都应该同步到内部的state.value,并通过执行props.onChange来触发更新
3. 当组件接受新的props的时候,将props.value反映给state.value
4. 在优先值发生变化后更新组件

有了以上原则,就可以实现一个装饰器,hybridCtrl,来将一个普通组件转换为一个混合组件

@hybridCtrl
class App extends React.Component {
static propTypes = {
value: React.PropTypes.any,
} state = {
_value: '',
} mapPropToState(controlledValue) {
// your can do some transformations from `props.value` to `state._value`
} handleChange(newVal) {
// it's your duty to handle change events and dispatch `props.onChange`
}
}

结论

1、为什么我们需要混合组件?

我们应该创建同时受控和非受控的组件,就像原生的元素那样。

2、混合组件主要思想是?

同时维护props.value和state.value的值。props.value在展示上拥有更高的优先级,state.value代表着组件真正的值。

混合组件的一个例子(作者是一村又一庄):

1、支持传入默认值;
2、可控:组件外部修改props可改变input组件的真实值及显示值;
3、非可控:输入框中输入值,可同时改变input组件的真实值及显示值。

示例代码地址:https://github.com/abell123456/hybrid-component

4. 受控组件和不受控组件的使用区别

5. 表单组件的几个重要属性

1.状态属性

React的form组件提供了几个重要的属性,用来显示组件的状态

value: 类型为text的input组件,textarea组件以及select组件都借助value prop来展示应用的状态
checked: 类型为radio或checkbox的组件借助值为boolean类型的selected prop来展示应用的状态
selected: 该属性可作用于select组件下面的option上,React并不建议这种方式表示状态.而推荐在select组件上使用value的方式

2.事件属性

当状态属性改变时会触发onChange事件属性.受控组件中的change事件与HTML DOM中提供的input事件更为类似

参考:https://segmentfault.com/a/1190000012404114
   https://blog.csdn.net/jianruoche/article/details/79238831
         https://blog.csdn.net/fendouzhe123/article/details/52121704
         https://www.cnblogs.com/aichenxy/p/6758004.html

React受控组件和非受控组件的更多相关文章

  1. React:受控组件与非受控组件混用实战 - 译文

    原文链接:React: hybrid controlled components in action 受控组件 非受控组件 混用受控组件和非受控组件 原则一 原则二 原则三 原则四 实施方案 总结 F ...

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

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

  3. react 表单(受控组件和非受控组件)

    我们知道表单元素与其他的普通DOM元素来说是不一样的,它们保存了自己的一些状态. 我们主要说的就是表单元素中的受控组件和非受控组件. 受控组件就是这个组件的状态是我们(react)控制的,这个组件的行 ...

  4. react中 受控组件和 非受控组件 浅析

    一 受控组件 顾名思义,受控 也就是能够被控制,简而言之也就是 该组件ui的显示或者内部state逻辑的变化依赖外部的 props的传入. 二 非受控组件 顾名思义,非受控,也就是内部的视图变化,st ...

  5. react第十一单元(受控组件和非受控组件-实现类似于vue双向绑定的功能)

    第十一单元(受控组件和非受控组件-实现类似于vue双向绑定的功能) #课程目标 理解因为react的单向数据流 理解表单组件会因为react数据流变的不好维护 理解受控组件与非受控组件的实质区别 理解 ...

  6. Vue父子组件及非父子组件如何通信

    1.父组件传递数据给子组件 父组件数据如何传递给子组件呢?可以通过props属性来实现 父组件: 子组件通过props来接收数据: 方式1: 方式2 : 方式3: 这样呢,就实现了父组件向子组件传递数 ...

  7. 学习React系列(四)——受控组件与非受控组件

    受控组件:通过组件的状态与属性的改变来控制组件 不可控组件:直接通过底层的dom来控制组件(具体来说就是通过绑定再底层dom上的方法来实现的,比如说ref,onChange) 受控组件 functio ...

  8. React 受控组件和非受控组件

    需求用户名自动获取 onChange用户状态发生改变 就获取值 就是时时获取值 使用onChange 点击按钮 获取密码 只要绑定了点击事件 就可以获取值 通过 let usercont=event. ...

  9. React组件之间通过Props传值的技巧(小案例,帮助体会理解props、state、受控组件和非受控组件等)

    本文重要是根据react小书上的一个很简单的例子改编的,加上自己的学习理解,希望可以通过实际案例让大家对概念有更清晰的理解,当然也希望能一块学习. import React,{Component} f ...

随机推荐

  1. unity中虚拟摇杆的实现

    实现效果: 实现: 使用NGUI添加虚拟摇杆背景和其子物体按钮,为按钮Attach  boxcollider和ButtionScript.为按钮添加如下脚本: 注意:其中的静态属性可以在控制物体移动的 ...

  2. Python2快速入门教程,只需要这十五张图片就够了!

    今天给大家分享的教程是适用于Python 2.7,但它可能适用于Python 2.Python 2.7将停止在2020中的支持. 与Python 2.7和3兼容的Python代码是完全可能的.通过使用 ...

  3. eclipse格式化

    一.eclipse格式化的必要性 1.便于阅读 2.便于协作 二.eclipse格式化快捷键 ctrl shift + F

  4. 爬虫2.1-scrapy框架-两种爬虫对比

    目录 scrapy框架-两种爬虫对比和大概流程 1. 传统spider爬虫 2. crawl型爬虫 3. 循环页面请求 4. scrapy框架爬虫的大致流程 scrapy框架-两种爬虫对比和大概流程 ...

  5. 解决CentOS: Failed to start The Apache HTTP Server.

    使用systemctl status httpd.service命令查看服务状态,发现有报错 然后将此配置文件/etc/httpd/conf.d/wordpress.conf的内容全部清空,修改为: ...

  6. [转载]CENTOS 6.0 iptables 开放端口80 3306 22端口

    原文地址:6.0 iptables 开放端口80 3306 22端口">CENTOS 6.0 iptables 开放端口80 3306 22端口作者:云淡风轻 #/sbin/iptab ...

  7. 【备忘】mysql常用操作汇总

    1.增删改查 // 插入一条数据 insert into tableName values('liu','bei') // 删除一条数据 delete from tableName where las ...

  8. js如何使浏览器允许脚本异步加载

    js如何使浏览器允许脚本异步加载 如果脚本体积很大,下载和执行的时间就会很长,因此造成浏览器堵塞,用户会感觉到浏览器“卡死”了,没有任何响应.这显然是很不好的体验,所以浏览器允许脚本异步加载,下面就是 ...

  9. 《剑指Offer》题十一~题二十

    十一.旋转数组的最小数字 题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如,数组{3, 4, 5, 1, 2}为{ ...

  10. 使用libpcab抓包&处理包

    #include <stdio.h> #include <stdlib.h> #include <strings.h> #include <string.h& ...