【问题标题】:Building a React Component that can be both Controlled and Uncontrolled构建一个可以控制和不受控制的 React 组件
【发布时间】:2019-06-20 22:27:24
【问题描述】:

我试图弄清楚受控和不受控的反应组件之间的区别,所以我想我会尝试构建一个可以是其中一个但不能同时是两者的控件。 <input> 使用的模式似乎是,如果您提供 value 道具,那么它将受到控制,否则不受控制,您可以使用 defaultValue 道具为不受控制提供默认值。

我的示例控件是一个简单的数字递增器/递减器,带有用于递增和递减的按钮以及显示当前值的标签。

我的问题是。

  1. 我是否以正确的方式解决了这个问题。
  2. 我已经编写了许多测试来涵盖我能想到的所有场景,这些都是有效的吗?我是否遗漏了任何一个。

我希望通过这个示例和任何反馈来彻底了解受控与非受控,以及何时使用它们。

我的代码和所有测试都在这个代码框https://codesandbox.io/s/kind-archimedes-cs0qy中可用

但我的组件在这里重复了方便...

    import React, { useState } from "react";

    export const NumberInput = ({ onChange, value, defaultValue, min, max }) => {
      const [uncontrolledVal, setUncontrolledVal] = useState(
        defaultValue || min || 0
      );

      if (
        (value && (value > max || value < min)) ||
        (defaultValue && (defaultValue > max || defaultValue < min))
      ) {
        throw new Error("Value out of range");
      }

      const handlePlusClick = () => {
        if (value && onChange) {
          onChange(value + 1);
        } else {
          const newValue = uncontrolledVal + 1;
          setUncontrolledVal(newValue);
          if (onChange) {
            onChange(newValue);
          }
        }
      };
      const handleMinusClick = () => {
        if (value && onChange) {
          onChange(value - 1);
        } else {
          const newValue = uncontrolledVal - 1;
          setUncontrolledVal(newValue);
          if (onChange) {
            onChange(newValue);
          }
        }
      };
      return (
        <>
          <button
            data-testid="decrement"
            disabled={value ? value === min : uncontrolledVal === min}
            onClick={() => handleMinusClick()}
          >
            {"-"}
          </button>
          <span className="mx-3 font-weight-bold">{value || uncontrolledVal}</span>
          <button
            data-testid="increment"
            disabled={value ? value === max : uncontrolledVal === max}
            onClick={() => handlePlusClick()}
          >
            {"+"}
          </button>
        </>
      );
    };

【问题讨论】:

  • 它很简单:controlled 输入是由你完全控制的,你处理每一个变化,这就是为什么你需要通过 valueonChangevalue 将代表正在屏幕上呈现的内容(可能是来自您的状态的值或来自容器的道具)和 onChange 来处理每个更改,因此您选择更新传递给 value 的状态。在uncontrolled 上,您只需要通过defaultValue 设置初始值并在需要时获取该值,您不关心它的更改以及它们的处理方式。
  • 好吧,我想我明白了,我的示例组件可以满足两者,但是什么时候可以使用不受控制的控制?
  • 假设我们有一个包含一些非常开放的输入的表单,我们不需要事先验证它们,然后我们可以将所有输入保持为不受控制,并在用户提交时获取值形式。例如,如果有一个名为“Name”的字段,我们不需要关心该字段内发生的每一个变化,只关心最终值。使用不受控制的代码会使代码更小一些,并且避免为您的输入编写句柄函数。也就是说,有时这只是个人选择使用什么。我个人更喜欢使用受控输入,但这是我的选择。

标签: reactjs


【解决方案1】:

对于像这样的自定义增量器,不存在不受控制的版本。不受控适用于 HTML 5 中的内置输入字段,例如文本字段、复选框或文件上传。

受控意味着输入的值由状态或道具值设置并使用自定义函数进行更新。不受控制的意味着它自己处理其值的更改,并且您必须在要使用它们时手动检索它们的值。

这可以使用像 ref 之类的东西来完成。

如果您将输入字段的值绑定到一个值,而没有提供更新其值 onChange 的函数,它将不会响应任何用户输入。但是,您可以为其提供 defaultValue,它仍会响应用户输入。

您可以在此处阅读更多信息:https://reactjs.org/docs/uncontrolled-components.html

这能回答你的问题吗?

【讨论】:

  • 不确定我是否理解为什么没有不受控制的组件之类的东西。我的实现似乎满足了这些条件。如果有不受控制的 html 5 输入的用例,是否也没有用于自定义控件的用例。只是想了解那个用例是什么。
  • 问题是,html 5 输入功能独立,无需控制它们。您可能希望以这种方式保留它们是有原因的(在我发布的链接中提到了)。没有理由制作您自己的不受控制的组件,因为这会使它们完全不起作用。
  • 好吧,我认为这是有道理的,所以我正在创建一个向导来创建一个新对象并使用不受控制的输入来确保我的新对象状态仅使用有效数据进行更新。相反,我应该在我的状态下允许无效数据,但如果某些页面上的字段包含无效数据,则阻止提交状态或向导继续。初始化向导时,我应该提供具有默认值或空值的模型吗?可选字段呢,如果我用未定义的值初始化一个输入,我很确定我在某处读到它,它将表现得不受控制并且不会响应未来的道具变化?
  • 我不太确定您所说的无效数据是什么意思,您是指不正确的数据类型还是类似于与向导将接受的值不匹配的值?一般来说,通常最好为您的输入提供与外部状态相关的 value 属性(即使您只是使用空字符串之类的东西对其进行初始化。然后您应该使用 React 事件侦听器更新该状态。最后您应该在使用向导进行或最终提交时验证输入是否正确。
猜你喜欢
  • 2020-03-30
  • 1970-01-01
  • 2016-09-22
  • 2020-11-04
  • 1970-01-01
  • 2022-01-01
  • 1970-01-01
  • 2017-07-20
相关资源
最近更新 更多