首页 > 其他分享 >react 受控组件与非受控组件

react 受控组件与非受控组件

时间:2022-10-28 09:36:16浏览次数:76  
标签:受控 const 方式 value 表单 react 组件

概述

React 中的受控组件和非受控组件都是针对于表单数据而言的。React 推荐使用受控组件来处理表单数据。

在受控组件中,表单数据由 React 组件的 state 管理。在非受控组件中,表单数据交由 DOM 节点处理,可以使用 ref 来从 DOM 中获取表单数据。

受控组件

React 的 state 是表单的数据源,并且渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。

function Form() {
  const [name, setName] = useState('');

  const onInputChange = event => setName(event.target.value);

  const onFormSubmit = event => {
    console.log('提交的数据 => ', name);
    event.preventDefault();
  };
  
  return (
    <form onSubmit={onFormSubmit}>
      <label>
        名字:
        <input type='text' value={name} onChange={onInputChange} />
      </label>
      <input type='submit' value='提交'/>
    </form>
  )
}

非受控组件

表单元素自己维护 state。可以使用 ref 获取表单数据.

function Form() {
  const inputElement = useRef(null);

  const onFormSubmit = event => {
    console.log('提交的数据 => ', inputElement.current.value);
    event.preventDefault();
  };

  return (
    <form onSubmit={onFormSubmit}>
      <label>
        名字:
        <input type='text' ref={inputElement} />
      </label>
      <input type='submit' value='提交'/>
    </form>
  )
}

默认值

在 React 渲染生命周期时,表单元素上的 value 将会覆盖 DOM 节点中的值,在非受控组件中,React 可以通过 defaultValue 属性赋予组件一个初始值。

return (
    <form onSubmit={onFormSubmit}>
      <label>
        名字:
        <input type='text' defaultValue='test' ref={inputElement} />
      </label>
      <input type='submit' value='提交'/>
    </form>
)

具有默认值(defaultValue)的表单元素,此时是否应该去控制后续的更新?

特殊的表单元素

textarea
在 React 中,textarea 使用 value 属性代替 HTML 中的子元素定义其文本。

<textarea value={value} onChange={handleChange} />

select
React 使用根 select 标签上的 value 属性定义选中,而不使用 selected 属性。

<select value={value} onChange={handleChange}>
    <option value="grapefruit">葡萄柚</option>
    <option value="lime">酸橙</option>
    <option value="coconut">椰子</option>
    <option value="mango">芒果</option>
</select>

<input type='file'
React 中 input type='file'> 始终是一个非受控组件,因为它的值只能由用户设定,而不能通过代码控制。

受控组件与非受控组件的选择

功能 受控组件 非受控组件
一次性的取值(例如:提交时
提交时验证
实时验证
有条件的禁用提交按钮
强制输入格式
一个数据的多个输入
动态输入

实际应用场景

场景1

页面有一些信息和一个编辑按钮,点击按钮出来一个弹窗,弹窗的内容是对信息的更改。

// 我们使用 Redux 来进行状态管理,数据来源为 props
const Information = props => {
  const [name, setName] = useState('');
  const [age, setAge] = useState(18);
  const nameInputElement = useRef(null);
  const ageInputElement = useRef(null);

  useEffect(() => {
    setName(props.name);
    setAge(props.age);
  }, [props]);

  return (
    <div>
      <div>
        <div>姓名:{name}</div>
        <div>年龄:{age}</div>
      </div>
      <Modal>
        <div>
          <label>
            姓名:
            {/* 方式1: 受控组件 */}
            <input type='text' value={name} onChange={e => setName(e.target.value)}/>

            {/* 方式2: 非受控组件 */}
            <input type='text' defaultValue={name} ref={nameInputElement}/>

            {/* 方式3: 非受控组件 */}
            <input type='text' defaultValue={name} onChange={e => setName(e.target.value)}/>

            {/* 方式4: 非受控组件 */}
            <input type='text' defaultValue={props.name} onChange={e => setName(e.target.value)}/>
            
          </label>
        </div>
        <div>
          <label>
            年龄:
            {/* 方式1: 受控组件 */}
            <input type='text' value={age} onChange={e => setAge(Number(e.target.value))}/>

            {/* 方式2: 非受控组件 */}
            <input type='text' defaultValue={age} ref={nameInputElement} />

            {/* 方式3: 非受控组件 */}
            <input type='text' defaultValue={age} onChange={e => setAge(Number(e.target.value))}/>

            {/* 方式4: 非受控组件 */}
            <input type='text' defaultValue={props.age} onChange={e => setAge(Number(e.target.value))}/>
            
          </label>
        </div>
      </Modal>
    </div>
  )
};

上面有4种方式:请注意:这四种方式都是在 中使用的

  • 方式1:在 中使用方式1的时候,弹窗出来之后对内容进行修改,之后点击取消关闭弹窗后,再点击编辑按钮,此时弹窗内容还是修改后的内容。所以如果使用方式1:受控组件来进行 时,需要在 closeModal 的方法中对内容进行重置。
  • 方式2:这种方式使用 ref 获取表单的值,但是有一个问题就是,获取用户的 age 是异步的,当拿到用户的 age 后,页面重新 render,但是此方式不会进行 age 的更新,故不使用此方式。
  • 方式3:这种方式使用 onChange 获取表单的值,但是这种方式和方式2有同样的问题,故不使用此方式。
  • 方式4:这种方式弹窗出来之后对内容的进行修改,之后点击取消关闭弹窗,再点击编辑按钮,内容是原有的内容,并且关闭时不需要重置。
  • 注:方式2与方式3的区别在于方式3会 render,而方式2不会 render

总结:方式1(受控组件)与方式4(非受控组件)都可以进行使用,方式1 closeModal 时需要重置修改内容

场景2

页面中有一个单选框(使用 ant Design 的 ) + 一个保存按钮,单选框选择性别,保存按钮可以对性别进行保存.

const Page = props => {
  const [sex, setSex] = setState('');
  const sexElement = useRef(null);

  useEffect(() => {
    setSex(props.sex);
  }, [props]);

  const save = () => {
    console.log('你的性别 -> ', sex);
  };

  return (
    <div>
      性别:

      {/* 方式1: 受控组件 */}
      <Radio.Group value={sex} onChange={e => setSex(e.target.value)}>
        <Radio.Button value='male'>男</Radio.Button>
        <Radio.Button value='female'>女</Radio.Button>
      </Radio.Group>

      {/* 方式2: 非受控组件 */}
      <Radio.Group defaultValue={sex} ref={sexElement}>
        <Radio.Button value='male'>男</Radio.Button>
        <Radio.Button value='female'>女</Radio.Button>
      </Radio.Group>

      {/* 方式3: 非受控组件 */}
      <Radio.Group defaultValue={sex} onChange={e => setSex(e.target.value)}>
        <Radio.Button value='male'>男</Radio.Button>
        <Radio.Button value='female'>女</Radio.Button>
      </Radio.Group>

      {/* 方式4: 非受控组件 */}
      <Radio.Group defaultValue={props.sex} onChange={e => setSex(e.target.value)}>
        <Radio.Button value='male'>男</Radio.Button>
        <Radio.Button value='female'>女</Radio.Button>
      </Radio.Group>
      
      <button onClick={save}>保存</button>
    </div>
  )
};

上面有4种方式:请注意:这四种方式都是在页面中使用的

  • 方式1:受控组件,没有任何问题
  • 方式2:异步获取 sex 之后页面没有进行更改,故不使用此方式。
  • 方式3:和方式2相同的问题,故不使用此方式。
  • 方式4:实践下来之后和方式2具有相同的问题
  • 总结:在页面中使用的时候乖乖用受控组件。

总结

我遇到了场景2中方式4的问题,所以我谷歌了一下,答案就是去研究受控组件,所有就诞生了这篇文章。另外千万不要在受控组件中使用 debounce,因为受控组件的一个特点就是实时。在非受控组件中,个人感觉 debounce 还是有必要使用一下的,从而优化了一下 render 的次数。
两者区别
1、受控组件

  • 受控组件依赖于状态
  • 受控组件的修改会实时映射到状态值上,此时可以对输入的内容进行校验
  • 受控组件只有继承React.Component才会有状态
  • 受控组件必须要在表单上使用onChange事件来绑定对应的事件

2、非受控组件

  • 非受控组件不受状态的控制
  • 非受控组件获取数据就是相当于操作DOM
  • 非受控组件可以很容易和第三方组件结合,更容易同时集成 React 和非 React 代码
  • 选择受控组件还是非受控组件

1、受控组件使用场景:一般用在需要动态设置其初始值的情况。例如:某些form表单信息编辑时,input表单元素需要初始显示服务器返回的某个值然后进行编辑。
2、非受控组件使用场景:一般用于无任何动态初始值信息的情况。例如:form表单创建信息时,input表单元素都没有初始值,需要用户输入的情况。

原文链接:https://www.jianshu.com/p/342b96b9b275

标签:受控,const,方式,value,表单,react,组件
From: https://www.cnblogs.com/coderz1/p/16834742.html

相关文章

  • 如何用界面组件DevExpress WPF创建Excel式的过滤功能?赶紧Get
    DevExpressWPF拥有120+个控件和库,将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpressWPF能创建有着强大互动功能的XAML基础应用程序,这些应用程序专......
  • 如何引用uni-app组件
    目的:找一个这样的卡片组件显示数据 在Dcloud里找到这样的插件并且引入    根据下方的说明来使用一、引入组件在右上方点击引入HbuilderX后,在需要应用的......
  • React + Ant Design 搭建个人博客
    react框架学的差不多了,就想搭建一个博客,沉淀一下!记录走过的点点滴滴!博客主要运用技术栈:react:项目主框架redux:状态管理reacr-router:前端路由控制es6:项目中的JS语......
  • react Hooks 钩子函数
    什么是Hooks?首先:React的组件创建方式,一种是类组件,一种是纯函数组件。React团队认为组件的最佳写法应该是函数,而不是类。但是纯函数组件有着类组件不具备的特点:纯函数......
  • c#的winform组件中,Menu和MenuStrip,以及MenuItem和ToolStripMenuItem有什么区别?
    https://zhidao.baidu.com/question/572383135.html首先从字面上理解,Menu就是菜单,MenuStrip是菜单栏,MenuItem是菜单项,ToolStripMenuItem是工具栏菜单项Menu是Form类的一个......
  • React进阶篇——十、高阶组件使用场景
    十、高阶组件使用场景操纵props在被包装组件接收props前,高阶组件可以先拦截到props,对props执行增加、删除或修改的操作,然后将处理后的props再传递给被包装组件,上一篇的......
  • Vitepress搭建组件库文档(下)—— 组件 Demo
    上文《Vitepress搭建组件库文档(上)——基本配置》已经讨论了vitepress搭建组件库文档的基本配置,包括站点Logo、名称、首页home布局、顶部导航、左侧导航等。本文进入......
  • react组件深度解读
    五、React核心是组件在React中,我们使用组件(有状态、可组合、可重用)来描述UI。在任何编程语言中,你都可以将组件视为简单的函数。React组件也一样,它的输入是props......
  • React实现一个简易版Swiper
    背景最近在公司内部进行一个引导配置系统的开发中,需要实现一个多图轮播的功能。到这时很多同学会说了,“那你直接用swiper不就好了吗?”。但其实是,因为所有引导的展示都是作......
  • React高级特性之Render Props
    renderprop是一个技术概念。它指的是使用值为function类型的prop来实现Reactcomponent之间的代码共享。如果一个组件有一个render属性,并且这个render属性的值为一个返......