浅谈React受控与非受控组件
背景
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受控与非受控组件的更多相关文章
- 七天接手react项目 —— 生命周期&受控和非受控组件&Dom 元素&Diffing 算法
生命周期&受控和非受控组件&Dom 元素&Diffing 算法 生命周期 首先回忆一下 vue 中的生命周期: vue 对外提供了生命周期的钩子函数,允许我们在 vue 的各个 ...
- Vue 中的受控与非受控组件
Vue 中的受控与非受控组件 熟悉 React 的开发者应该对"受控组件"的概念并不陌生,实际上对于任何组件化开发框架而言,都可以实现所谓的受控与非受控,Vue 当然也不例外.并且 ...
- 浅谈React
浅谈react react是什么?其官网给出了明确定义:A JavaScript library for building user interfaces,一个用于构建用户界面的JavaScript库 ...
- 【转】浅谈React、Flux 与 Redux
本文转自<浅谈React.Flux 与 Redux>,转载请注明出处. React React 是一个 View 层的框架,用来渲染视图,它主要做几件事情: 组件化 利用 props 形成 ...
- 浅谈React工作原理
浅谈React工作原理:https://www.cnblogs.com/yikuu/p/9660932.html 转自:https://cloud.tencent.com/info/63f656e0b ...
- 浅谈react受控组件与非受控组件
引言 最近在使用蚂蚁金服出品的一条基于react的ant-design UI组件时遇到一个问题,编辑页面时input输入框会展示保存前的数据,但是是用defaultValue就是不起作用,输入框始终为 ...
- React学习之受控和非受控组件
受控组件是通过事件完成对元素value的控制,反之就是非受控组件. 1.受控组件的value通过onChange事件来改变,非受控不需要通过事件来改变value. 2.受控组件通过事件通过setSta ...
- react 表单受控和非受控
参见:https://goshakkk.name/controlled-vs-uncontrolled-inputs-react/ 非受控: onSubmit = ()=>{ const val ...
- 浅谈React数据流管理
引言:为什么数据流管理如此重要?react的核心思想就是:UI=render(data),data就是我们说的数据流,render是react提供的纯函数,所以用户界面的展示完全取决于数据层.这篇文章 ...
随机推荐
- Careercup 论坛上较有意思的题目整理
# 数据结构类 ### 线段树 segment tree http://www.careercup.com/question?id=5165570324430848 找区间内的value的个数 二维线 ...
- Sqlserver添加或更新数据SQL
Merge into [tableName] as t Using(select [@id] as tid) as t1 on t1.tid=t.id when matched then update ...
- NGUI 修改Shader支持灰色滤镜
之前有人做过,不过效率不高: http://blog.csdn.net/onerain88/article/details/12197277 他的代码: fixed4 frag (v2f i) : ...
- Android 布局之RelativeLayout
Android 布局之RelativeLayout 1 RelativeLayout简介 RelativeLayout是相对布局. RelativeLayout布局属性 1.1 与parent相对的属 ...
- spring websocket源码分析
什么是websocket? 摘录于wiki[1]: WebSocket is a protocol providing full-duplex communication channels over ...
- tar exclue文件夹
tar zcvf logs.tar.gz logs --exclude=logs/log1
- [Node.js] 也说this
原文地址:http://www.moye.me/2014/11/21/也说this/ 引子 Any sufficiently advanced technology is indistinguisha ...
- css实现高度不固定的div元素模块在页面中水平垂直居中
<!DOCTYPE html><html> <head> <title>Laravel</title> <link ...
- IT168关于敏捷开发采访
1.我们知道敏捷开发是一套流程和方法的持续改进,通过快速迭代的方式交付产品,从而控制和降低成本.但是在实行敏捷初期,往往看不到很好的效果.这里面,您觉得问题主要出在哪?团队应如何去解决问题?金根:我认 ...
- 写出优美代码的两个方式:一步到位VS迭代优化
最近把手头这个安卓APP的所有事务性方法都写完了,有了以下体会,新手体会,老鸟轻拍 想写成优美代码的人一般都会有这样的想法: 一定要在写每一句代码,写每一个方法,构造每一个类的时候,都要记得优化: ...