React:创建同时受控与非受控的组件
来源:互联网 发布:catia软件的应用 编辑:程序博客网 时间:2024/04/29 13:30
提示:考虑到react的少状态设计,这里提到的方案可能是反模式。
我们都知道,有许多的web组件可以被用户的交互发生改变,比如:<input>
,<select>
,或者是我现在正在使用的富文本编辑器。这些组件在日常的开发中很不显眼,我们可以很轻易的通过输入一些内容或者设置元素的value
属性来改变组件的值。但是,因为React是单向数据流绑定的,这些组件可能会变得失控
:
1.一个维护它自己
state
里的value值的<Input>
组件无法从外部被修改;
2.一个通过props
来设置value
值的<Input>
组件只能通过外部控制来更新。
最终,React提出了两个概念:受控组件和非受控组件。
受控组件
一个受控的
<input>
组件都有一个value
属性。渲染一个受控的<input>
会展示出value属性的值。
一个受控的组件不会维护它自己内部的状态,组件的渲染单纯的依赖于props。
也就是说,如果我们有一个通过props
来设置value
的<input>
组件,不管你如何输入,它都只会显示props.value
。换句话说,你的组件是只读的。
很神奇的是,一些非常流行的组件也会有这样的行为。可以看下react工具箱集合,如果我们从<Dropdown />
组件中移除value
属性,那么该组件会变成一个‘死的’(无法被修改的)dropdown – 谁会爱上一个死的家伙?
当我们在处理一个受控组件的时候,你应该始终传一个value
属性进去,并且注册一个onChange
的辅助方法来让组件变得可变,这样的话,上面组件(译者注:就是包含input或者textarea的外围组件)的state
就会变得复杂和混乱。
非受控组件
一个没有
value
属性的<input>
就是一个非受控组件。通过渲染的元素,任意的用户输入都会被立即反映出来。一个非受控的组件自己维护自己的
state
。
很好,现在我们就可以像原生的元素那样进行操作了。等等,那我如何修改input元素的值呢,就像之前简单的js操作:input.value = xxx
那样。
悲剧的是你无法从外面来修改value值,因为它是不受控的!
混合组件
那么,为什么不创建一个既受控
又不受控
的组件呢?我们可以根据react受控(非受控)组件的定义里得到一些启发:
原则1
props.value
总是有比内部state.value
跟高的优先级。
当props.value
被设置以后,我们应该总是拿props.value
来渲染而不是state.value
,因此我们可以定义一个displayValue
的getter属性:
get displayValue() { return this.props[key] !== undefined ? this.props[key] : this.state[internalKey];}
然后再render
函数中:
render() { return (<div>{this.displayValue}</div>);}
原则2
组件中所有的变化都应该同步到内部的
state.value
,并通过执行props.onChange
来触发更新。
将值同步到state.value
可以保证组件即使是非受控的也总能渲染出最新的值。通过请求一个外部的更新会告诉上面的组件基于props.value
执行修改,这样受控的组件也能渲染出正确的值。
handleChange(newVal) { if (newVal === this.state.value) return; this.setState({ value: newVal, }, () => { this.props.onChange && this.props.onChange(newVal); });}
原则3
当组件接受新的props的时候,将
props.value
反映给state.value
。
为了能修改内部的value以及在handleChange
中执行正确的操作,将props.value
和state.value
进行同步是非常重要的:
componentWillReceiveProps(nextProps) { const controlledValue = nextProps.value; if (controlledValue !== undefined && controlledValue !== this.state.value ) { this.setState({ value: controlledValue, }); }}
原则4
在优先值(译者注:props.value优先于state.value)发生变化后更新组件。
这样能阻止组件发生不必要的二次渲染,比如,一个受控的组件在内部state.value
发生变化的时候不应该触发重新渲染(译者注:受控的只有在props.value发生变化的时候才触发修改)。
shouldComponentUpdate(nextProps, nextState) { if (nextProps.value !== undefined) { // controlled, use `props.value` return nextProps.value !== this.props.value; } // uncontrolled, use `state.value` return nextState.value !== this.state.value;}
解决方案
有了以上的原则后,我们可以像this gist 那样创建一个装饰器。可以这样用:
@hybridCtrlclass 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
代表着组件真正的值。
P.S. 在翻译文章后,忍不住写了个input组件的例子试了下,支持以下功能:
1、支持传入默认值;
2、可控:组件外部修改props
可改变input组件的真实值及显示值;
3、非可控:输入框中输入值,可同时改变input组件的真实值及显示值。
示例代码地址:https://github.com/abell123456/hybrid-component
- React:创建同时受控与非受控的组件
- React受控组件与非受控组件
- React受控组件与非受控组件
- 浅谈react受控组件与非受控组件
- 浅析React中的受控组件和非受控组件
- react混合受控组件
- Spring受控异常与非受控异常
- React.js 官方文档摘记:非受控组件
- 在React中受控和非受控的表单输入并不需要太复杂
- react学习-受控组件(controlled components)
- 受控异常 VS 非受控异常
- 受控异常 VS 非受控异常
- 受控异常 VS 非受控异常
- 翻译 | 玩转 React 表单 —— 受控组件详解
- 访问受控的dom节点
- 受控访问
- 受控wifi接入的网络编程
- 受控制的球,随点击运动
- tmpl 模板化引擎加载数据 Jquery
- 饼图与柱状图的topN处理
- 关于mybatis扫描所有namespace时报错,最终原因是resultMap不能使用(我的错误记录)
- NSURL学习
- 【beautifulsoup】python标准库解析器解析网页问题解决
- React:创建同时受控与非受控的组件
- LightOJ 1021 Painful Bases 【状压DP+数位DP】
- android studio add fragment from layout
- Maven 手动添加 JAR 包到本地仓库
- 图解HTTPS
- PHPExcel讀取excel數據
- 带有 mask 的 OTSU 自适应阈值
- C++程序crash几种情况
- .NET 实现页面点赞功能