antd表单控件的设计思想

antd对于form中输入控件的抽象十分简单,只要能接收value和onChange属性的组件都可以成为Form.Item的子组件,为Form对应的字段提供值。对于输入控件的抽象我认为这已经达到了极致,事件(onChange)产生值(value)。事件向上,值向下,完全符合React哲学。

如何实现一个标准的输入组件?

对于输入组件首先需要具备接收value和onChange属性的能力,这两个属性被提供的情况下这个组件被称为受控组件,它受到父组件控制,状态来自父组件。当父组件没有提供value的情况下该组件是非受控组件,有自己的状态。

是否受控主要取决于value属性是否提供,因为value决定了组件当前的状态,当前状态被父组件控制,所以称之为受控组件。

输入组件的状态是会改变的,最常见的方式就是来自用户行为,例如在input中输入内容,该组件的状态(value)就会改变。

  1. 因为组件可以作为非受控组件,所以组件自身有innerValue和setInnerValue用于展示和响应用户输入。
  2. 如果父组件没有提供value
    1. 组件使用自身的setInnerValue响应用户输入,改变自身状态innerValue
    2. 如果父组件提供onChange,在setInnerValue同时触发onChange事件通知父组件
  3. 如果父组件提供了value,组件失去了决定自身状态的能力(自身不会直接响应用户输入)
    1. 如果父组件提供onChange函数,则使用该函数响应用户输入
    2. 组件自身的setInnerValue不会响应用户输入(setInnerValue的作用是修改innerValue,因为有父组件的value,innerValue会响应value的变化,所以setInnerValue不应该直接修改innerValue导致其和value不一致)
function Input (props) {
	const [innerValue, setInnerValue] = useState(props.value);

	useEffect(() => {
		if ('value' in props) setInnerValue(props.value)
	}, [props.value])

	function handleChange (ev) {
		if (!('value' in props)) {
			setInnerValue(ev.target.value)
		}

		props.onChange?.(ev.target.value)
	}
	
	return <input value={innerValue} onChange={handleChange} />
}

跨组件响应

<Form>
	<Form.Item name="name">
		<div>
			<Input />
		</div>
	</Form.Item>
</Form>

如果按照上面的理论,因为中间隔了一层,按说Form是收不到Input的响应的.
但是事实是可以收到响应,因为它本质上是通过事件完成的响应。而不只是属性onChange和value。
Form.Item会为childNode添加onChange事件监听,当input内容发生改变的时候会触发onChange事件,即可通过这个事件拿到对应值。
antd的策略是拿到onchange的元素的value属性返回,如果没有那么就直接事件将入参返回。

Form.Item的onChange事件和value无法起作用

上面说了onChange会被Form.Item写给子组件,所以子组件只能有一个,这也是这个方案的限制,如果有两个,到底哪个元素会触发onchange?这个也不好说。所以子组件只能有一个。
又因为onChange事件不能在自定义组件的节点上冒泡,所以导致下例失效,必须要组件Abc手动执行onChange才可以帮助Form.Item拿到最新的值。

function Abc() {
	return <input />
}

<Form>
	<Form.Item name="name">
		<Abc />
	</Form.Item>
</Form>

Form.Item的value无法向下传递

<Form>
	<Form.Item name="name">
		<div>
			<input />
		</div>
	</Form.Item>
</Form>

Form.Item的子组件是真实的dom情况下input的onChange事件可以被添加到div上的onChange监听,也就是input的值可以更新到Form中,但是这种形式的结构会导value的传递失效,无法响应通过Form.setValues设置的值。也就是value的修改无法回显给input元素。这种情况下虽然Form中的值和input中的看起来一样,但是input的中的值其实并不受控。

这种结构主要来源于antd对于react事件系统的理解。这很精髓。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值