将键盘输入限制为 A-Z,而不是 React 组件上的任何键盘输入

Limiting keyboard inputs to A-Z as opposed to any keyboard input on React component

我刚刚遇到一个组件,我正在努力了解它,但基本上我关心的值是 allowForClassification,这是一个传递给子组件的布尔值并决定我们是否显示一个按钮。 (基本上意味着只有在用户输入一个字母后才会出现“查找”按钮——目前即使是空格键也会触发该按钮出现)。

但是我很难理解在这个组件中到底在哪里进行了检查,我知道如果 canClassify & !classifyInProgress 在底部 allowForClassification 设置为 true被退回,但我找不到他们在哪里检查键盘输入,任何建议都会很有帮助。

const getCcceValues = (object?: FormObjectModel | null) => {
  const ccceInput: $Shape<CcceInput> = {};

  if (!object) {
    return {};
  }

  const ccceValues = object.attributeCollection.questions.reduce(
    (acc, attribute) => {
      const fieldEntry = ccceBeInformedFieldMap.get(attribute.key);

      if (fieldEntry) {
        acc[fieldEntry] = attribute.value;
      }

      return acc;
    },
    ccceInput
  );

  // ready to perfom classification based on user input
  const canClassify = Object.values(ccceValues).every(Boolean);

  return { canClassify, ccceValues };
};

export const useCcceEmbed = (
  ccceResultAttribute: AttributeType,
  onChange: Function
): CcceHook => {
  const { object, form } = useFormObjectContext();
  const [resultCode, setResultCode] = useState<string | null>(null);

  const { canClassify, ccceValues } = getCcceValues(object);

  const { handleSubmit } = useFormSubmit();

  const [showModal, setShowModal] = useState<boolean>(false);

  const handleCloseModal = useCallback(() => setShowModal(false), []);
  const handleShowModal = useCallback(() => setShowModal(true), []);

  // state value to keep track of a current active classification
  const [classifyInProgress, setClassifyInProgress] = useState<boolean>(false);

  const handleResult = useCallback(
    (result) => {
      if (result?.hsCode) {
        onChange(ccceResultAttribute, result.hsCode);

        setResultCode(result.hsCode);
        setClassifyInProgress(false);

        handleSubmit(form);
      }
    },
    [ccceResultAttribute, form, handleSubmit, onChange]
  );

  const handleCancelClassify = useCallback(() => {
    setClassifyInProgress(false);
    handleCloseModal();
  }, [handleCloseModal]);

  const handleClassify = useCallback(
    (event?: SyntheticEvent<any>) => {
      if (event) {
        event.preventDefault();
        console.log("scenario 1");
      }

      if (classifyInProgress || !canClassify) {
        console.log("scenario 2");
        return;
      }

      const ccce = window.ccce;

      if (!ccceValues || !ccce) {
        throw new Error("Unable to classify - no values or not initialised");
        console.log("scenario 3");
      }

      setClassifyInProgress(true);

      const classificationParameters = {
        ...ccceValues,
        ...DEFAULT_EMBED_PROPS,
      };

      ccce.classify(
        classificationParameters,
        handleResult,
        handleCancelClassify
      );
    },
    [
      classifyInProgress,
      canClassify,
      ccceValues,
      handleResult,
      handleCancelClassify,
    ]
  );

  return {
    allowForClassification: canClassify && !classifyInProgress,
    classifyInProgress,
    dataProfileId,
    embedID: EMBED_ID,
    handleCancelClassify,
    handleClassify,
    handleCloseModal,
    handleShowModal,
    isDebugMode,
    resultCode,
    shouldShowModal: showModal,
  };
};

解决方案

此代码中缺少很多内容,可能有更好的方法来执行此操作。但这是我想出的。

我们可以评估输入值是否包含字符,而不是评估输入值是否为空。

替换此行:

const canClassify = Object.values(ccceValues).every(Boolean);

用这两行:

const regex = new RegExp('\w', 'g');

const canClassify = Object.values(ccceValues).every(value => regex.test(value));

或者这一行:

const canClassify = Object.values(ccceValues).every(value => /\w/g.test(value))

为什么是那条线?

我通过逆向工作得出了那个解决方案。这是我通过代码到达正确位置所采取的所有步骤。

allowForClassification: canClassify && !classifyInProgress,
如果 canClassifytrueclassifyInProgressfalse,则

allowForClassificationtrue。如果我们已经在执行分类,我们不想分类。这就说得通了。所以这是我们关心的 canClassify 值。

const { canClassify, ccceValues } = getCcceValues(object);

canClassify来自getCcceValues函数,其值可能取决于object.

的值
const { object, form } = useFormObjectContext();

object 来自一些外部挂钩,这对我来说是死胡同,因为我看不到该代码。但请注意,这里 可能 有一些替代解决方案。

const canClassify = Object.values(ccceValues).every(Boolean);

.every(Boolean) 与写成长格式 .every(value => Boolean(value)) 的含义相同。如果 ccceValues 的每个值在转换为 Boolean 时都是 true,则 canClassifytrue。这意味着该值不是以下任何值:false0-00n""nullundefined, NaN. (source)

const ccceInput: $Shape<CcceInput> = {};

const ccceValues = object.attributeCollection.questions.reduce(
    (acc, attribute) => {
      const fieldEntry = ccceBeInformedFieldMap.get(attribute.key);

      if (fieldEntry) {
        acc[fieldEntry] = attribute.value;
      }

      return acc;
    },
    ccceInput
);

ccceValues 有点复杂。它由 array .reduce() 操作创建。它以 ccceInput 的初始值开始,这是一个空对象 {}。在迭代的每一步,它可能会在该对象上设置一个 属性。最后的值就是设置了一堆属性后的对象。

回调中的参数是 acc——我们正在构建的对象,以及 attribute——questions 数组的当前元素。我们设置的键是 fieldEntry,值是 attribute.value.

请记住,canClassify 检查所有 是否“真实”。所以关键不重要。我们只关心值(attribute.value).


为什么是那个代码?

但是反过来,我们了解到当 canClassify/allowForClassifiationtrue 时,在您希望它是 false 的情况下,这是因为当您希望它是 false 时,有些值 Boolean(attribute.value)true。这是为什么?

我将做出一个合乎逻辑的假设,即 attribute.value 变量包含用户在框中键入的字符串。

记住我之前所说的 Boolean 选角。空字符串 ''false,所有其他字符串为 true。因此,如果 object.attributeCollection.questions 中至少有一个用户未输入任何内容的框,则 allowForClassification 将是 false,因为 attribute.value 将是 ''

只要用户点击最后一个框中的空格键,attribute.value 就会变成 ' '此字符串的 Boolean 值为 true,因此 allowForClassification 现在为 true

但是您想应用不同的规则集。当且仅当它包含至少一个字母时,您才会将值视为 true。我们可以使用简单的 regular expression 来检查。我不确定您的确切规则集(数字可以吗?下划线呢?accented/non-Latin 字符呢?),因此您可能需要调整正则表达式。但这应该让你完成了 99%。

const regex = new RegExp('\w', 'g');
// can also be written as: const regex = /\w/g;

我正在使用 \w 字母数字 character class and the g global match flag 来匹配字符串中任意位置的任何字母数字字符。

要检查字符串是否匹配此正则表达式,请使用 .test() 方法。

const hasCharacter = regex.test(someString);

我们想在 canClassify.every() 回调中使用此函数,而不是 Boolean 构造函数。所以我们写:

const canClassify = Object.values(ccceValues).every(value => regex.test(value));