如果我将组件放在我的标签中,则无法选择下拉选项

Dropdown option cannot be selected if I put the component inside my label

为什么当我将 Dropdown 组件放入 <label> 标签中时,它不起作用?下拉列表显示选项,但如果您单击其中一个,则选择不是 working/displayed。

有什么建议吗?

    export default function App() {
     
      return (
        <div>
          <div className="mt-10 mb-3 h-6 text-md uppercase font-bold>
            People
          </div>
          <button type="button" onClick={addInvitee}>
            +Add menu
          </button>
          <form onSubmit={handleSubmit}>
            {invited.map(({ age, email, id, location, name }, index) => (
              <div key={id}>
                <div className="grid grid-cols-3 gap-5">
                  <label className="mr-3 h-6 text-md font-bold">
                    Names:
                    <input
                      type="text"
                      value={name}
                      placeholder="Names"
                      name="name"
                      onChange={updateInvitee(id)}
                    />
                  </label>
                 //other inputs with the exact same pattern
                  <label>
                    Choice:
                    <Dropdown className="w-3/5" options={CHOICE} isMulti={false} />
                  </label>
                 ...//other inputs
          </form>
        </div>
      );
    }

Dropdown.jsx

import React, { useState } from "react";
import Select from "react-select";
import Tag from "./Tag";

export default function Dropdown({
  className,
  style,
  options,
  styleSelect,
  defaultValue,
  isMulti = false
}) {
  const [selected, setSelected] = useState(defaultValue);

  const styles = {
    select: {
      width: "100%",
      maxWidth: 200
    }
  };

  return (
    <div style={style}>
      {selected && isMulti === false ? (
        <Tag
          selected={selected}
          setSelected={setSelected}
          styleSelect={styleSelect}
        />
      ) : (
        <Select
          className={className}
          style={styles.select}
          value={selected}
          onChange={setSelected}
          options={options}
          isMulti={isMulti}
        />
      )}
    </div>
  );
}

这是我的CodeSandbox

首先要注意以下几点:

基于此图像,来自沙箱的控制台片段,它显示 selection 发生,但立即被清除。

这是什么原因?嗯..让我们看看。

考虑这个代码片段:

<label>
  Press the text 
  <br /><br />
  <button onClick="console.log('button-clicked')">Button</button>
</label>

在这里,<button> 被放置在 <label> 中。您是否注意到,当您单击 press the text 时,buttononClick 会被触发? ...但是为什么?

嗯,默认情况下,<label> 是一个可获得焦点的 html 元素,当获得焦点时,它会触发放置在其中的任何表单控件元素。

那么这与您的代码有什么关系?

您的 <Tag> 组件 onClick={() => setSelected(null)} 中有这行代码,这就是问题所在。当你选择一个 selection 时,selected 得到更新,组件 re-renders 并显示你的 <Tag> 组件......但是事件仍然再次冒泡树直到它到达<label> 元素。请记住,此时显示的不再是 <Select> 组件,而是 <Tag> 组件。你猜怎么着? <label> 获得焦点并触发 <Tag> 组件内的 <button>,该组件清除 (setSelected(null)) selected 状态 属性。 selected清除后,<Dropdown>分量re-renders和<Select>分量再次显示。

当您尝试 select 时,这种情况会一直持续下去,然后重复该过程。

所以,从您的代码中...只需在此处删除它 onClick={() => setSelected(null)},您就会发现它会起作用。所以你只需要解决如何清除 selected,但我在下面提出了一个解决方案。


解决方案

在您的 <Dropdown> 组件中,我们应该尝试防止事件冒泡。因此,您需要做的就是在 <div>

中添加以下 onClick={e=>e.preventDefault()}
<div style={style} onClick={(e) => e.preventDefault()}>
      {selected && isMulti === false ? (
        <Tag
          selected={selected}
          setSelected={setSelected}
          styleSelect={styleSelect}
        />
      ) : (
        <Select
          className={className}
          style={styles.select}
          value={selected}
          onChange={setSelected}
          options={options}
          isMulti={isMulti}
        />
      )}
    </div>

Here's the original sandbox with the solution applied.