我们应该如何优雅的处理 React 中受控与非受控

引言

大家好,我是19组清风。有段时间没有和大家见面了,最近因为有一些比较重要的事情(陪女朋友和换了新公司)在忙碌所以销声匿迹了一小段时间,

后续会陆陆续续补充之前构建 & 编译系列中缺失的部分,提前预祝大伙儿圣诞节快乐!

受控 & 非受控

今天来和大家简单聊聊 React 中的受控非受控的概念。

提到受控和非受控相信对于使用过 React 的朋友已经老生常谈了,在开始正题之前惯例先和大家聊一些关于受控 & 非受控的基础概念。

当然,已经有基础的小伙伴可以略过这个章节直接往下进行。

受控

在 HTML 中,表单元素(如<input>、 <textarea> 和 <select>)通常自己维护 state,并根据用户输入进行更新。而在 React 中,可变状态(mutable state)通常保存在组件的 state 属性中,并且只能通过使用 setState()来更新。

我们可以把两者结合起来,使 React 的 state 成为“唯一数据源”。渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。

上述的描述来自 React 官方文档,其实受控的概念也非常简单。通过组件内部可控的 state 来控制组件的数据改变从而造成视图渲染。

这种模式更像是 Vue 中在表单元素中的常用处理模式,举一个简单的例子,比如:

import { FC } from 'react';

interface InputProps<T = string> {value: T;onChange: (value?: T) => void;
}

const Input: FC<InputProps> = (props) => {const { onChange, value = '', ...rest } = props;const _onChange = (e: React.ChangeEvent<HTMLInputElement>) => {const value = e.target.value;onChange && onChange(value);};return <input value={value} onChange={_onChange} {...rest} />;
};

export default Input; 

上述的代码非常简单,我们声明了一个名为 Input 的自定义输入框组件,但是 Input 框中的值是由组件中的 controllerState 进行控制的

这也就意味着,如果组件外部的状态并不改变(这里指组件的 props 中的 value)时,即使用户在页面上展示的 input 如何输入 input 框中渲染的值也是不会发生任何改变的。

当然,无论是通过 props 还是通过 state 只要保证表单组件的 value 接受的是一个非 undefined 的状态值,那么该表单元素就可以被称为受控(表单中的值是通过组件状态控制渲染的)。

非受控

既然存在受控组件,那么一定存在相反非受控的概念。

在大多数情况下,我们推荐使用 受控组件 来处理表单数据。在一个受控组件中,表单数据是由 React 组件来管理的。另一种替代方案是使用非受控组件,这时表单数据将交由 DOM 节点来处理。

熟悉 Ant-Design 等存在表单校验的 React 组件库的朋友,可以稍微回忆下它们的表单使用。

// ant-design 官方表单使用示例
import React from 'react';
import { Button, Checkbox, Form, Input } from 'antd';

const App: React.FC = () => {const onFinish = (values: any) => {console.log('Success:', values);};const onFinishFailed = (errorInfo: any) => {console.log('Failed:', errorInfo);};return (<Formname="basic"labelCol={
  { span: 8 }}wrapperCol={
  { span: 16 }}initialValues={
  { remember: true }}onFinish={onFinish}onFinishFailed={onFinishFailed}autoComplete="off"><Form.Itemlabel="Username"name="username"rules={[{ required: true, message: 'Please input your username!' }]}><Input /></Form.Item><Form.Itemlabel="Password"name="password"rules={[{ required: true, message: 'Please input your password!' }]}><Input.Password /></Form.Item><Form.Item name="remember" valuePropName="checked" wrapperCol={
  { offset: 8, span: 16 }}><Checkbox>Remember me</Checkbox></Form.Item><Form.Item wrapperCol={
  { offset: 8, span: 16 }}><Button type="primary" htmlType="submit">Submit</Button></Form.Item></Form>);
};

export default App; 

虽然说 React 官方推荐使用受控组件来处理表单数据,但如果每一个表单元素都需要使用方通过受控的方式来使用的话对于调用方来说的确是过于繁琐了。

所以大多数 React Form 表单我们都是通过非受控的方式来处理,那么所谓的非受控究竟是什么意思呢。我们一起来看看。

所谓非受控简单来说也就指的是表单元素渲染并不通过内部状态数据的改变而渲染,而是交由源生表单内部的 State 来进行自由渲染。

这其实是一种和受控组件完全相反的概念,比如:

import { FC } from 'react';

interface InputProps<T = string> {defaultValue?: T;
}

const Input: FC<InputProps> = (props) => {const { defaultValue } = props;return <input defaultValue={defaultValue} />;
};

export default Input; 

上述我们重新定义了一个名为 Input 的非受控组件,此时当你在使用该 Input 组件时,由于 defaultValue 仅会在 input 元素初始化时进行一次数据的初始化。

之后当用户在页面上的 input 元素中输入任何值表单值都会跟随用户输入而实时变化而并不受任何组件状态的控制,这就被称为非受控组件。

当然相较于受控组件获取值的方式,非受控组件获取的方式就会稍微显得繁琐一些,非受控组件需要通过组件实例也就是配合 ref 属性来获取对应组件/表单中的值,比如:

import { FC, useRef } from 'react';

interface InputProps<T = string> {defaultValue?: T;
}

const Input: FC<InputProps> = (props) => {const { defaultValue } = props;const instance = useRef<HTMLInputElement>(null);const getInstanceValue = () => {if (instance.current) {alert(instance.current.value);}};return (<div><input ref={instance} defaultValue={defaultValue} /><button onClick={() => getInstanceValue()}>获取input中的值</button></div>);
};

export default Input; 

上边的代码中,我们需要获取 unController input 的值。需要通过 ref 获得对应 input 的实例之后获得 input 中的值。

重要区分点

上边我们聊到了 React 中的受控和非受控的概念,在 React 中区分受控组件和非受控组件有一个最重要的 point 。

在 React 中当一个表单组件,我们显式的声明了它的 value (并不为 undefined 或者 null 时)那么该表单组件即为受控组件。

相反,当我们为它的 value 传递为 undefined 或者 null 时,那么该组件会变为非受控(u

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值