【问题标题】:react check box not rendering correctly反应复选框未正确呈现
【发布时间】:2021-11-09 15:03:13
【问题描述】:

我正在尝试创建一个表示图块的反应组件。

这个组件只是一个由标签和复选框组成的div。

我遇到的问题是我可以单击组件上的任何位置,并且状态会像通常那样更改(例如:通过单击组件,我可以选中或取消选中复选框)。但是当我点击复选框时没有任何反应。

这是我新创建的组件代码:

const Tile = ({ title }) => {
  const [selected, setSelected] = useState(false);
  useEffect(()=>{
    console.log(selected)
  },[selected])
  return (
    <>
      <div className="tile" onClick={ev=>setSelected(curr=>!curr)}>
        <label>{title}</label>
        <input
          type="checkbox"
          checked={!!selected}
          onChange={ev=>{setSelected(curr=>!curr)}}
        ></input>
      </div>
    </>
  );
};

在这里我在我的 App.js 中使用它:

return (
    <Container>
      <Row>
        <Col md={4}>
          <Tile title="USA"></Tile>
          <Tile title="MOROCCO"></Tile>
          <Tile title="FRANCE"></Tile>
        </Col>
        <Col md={8}>
          <h1>Hello</h1>
        </Col>
      </Row>
    </Container>

最后这是我的 css :

      body {
        padding-top: 20px;
        font-family: "Poppins", sans-serif;
        background-color: cornsilk;
      }
      .tile {
        position: relative;
        display: block;
        width: 100%;
        min-height: fit-content;
        background: bisque;
        padding: 8px;
        margin: 1px;
      }
      .tile input[type="checkbox"] {
        position: absolute;
        top: 50%;
        right: 0%;
        transform: translate(-50%, -50%);
      }

编辑:在标签上使用 htmlFor 修复的问题是标签是可点击的,而复选框是可点击的,但它们之间的空间不是。我希望整个组件都可以点击

【问题讨论】:

  • 当您在 &lt;div&gt; 元素上使用 onClick 事件尝试将它们替换为 &lt;buttons&gt; 时会发生这种情况。
  • 我将 div 更改为按钮,但发生了同样的事情.. 组件响应所有地方的点击事件,但在复选框上
  • @AmineHammou,检查我的答案和代码沙箱,看看是否是您的想法。
  • @AmineHammou,我的答案已更新。

标签: javascript reactjs checkbox use-state


【解决方案1】:

将 htmlFor 属性添加到标签并将 id 添加到匹配该 htmlFor 值的输入。

在您的情况下,Tile 组件是:

const Tile = ({ title }) => {
  const [selected, setSelected] = useState(false);
  useEffect(()=>{
    console.log(selected)
  },[selected])

  return (
    <>
      <div className="tile" onClick={ev=>setSelected(curr=>!curr)}>
        <label htmlFor={title}>{title}</label>
        <input
          id={title}
          type="checkbox"
          checked={!!selected}
          onChange={ev=>{setSelected(curr=>!curr)}}
        ></input>
      </div>
    </>
  );
};

【讨论】:

  • 标签已经可以点击了..我的问题是复选框是不响应点击事件的那个
【解决方案2】:

您的div 上不需要onClick

const Tile = ({ title }) => {
  const [selected, setSelected] = useState(false);
  useEffect(() => {
    console.log(selected);
  }, [selected]);
  return (
    <>
      <div className="tile" onClick={() => setSelected((curr) => !curr)}>
        <label htmlFor={title}>{title}</label>
        <input
          id={title}
          type="checkbox"
          checked={!!selected}
          onChange={(ev) => {}}
        />
      </div>
    </>
  );
};

我做了一个代码沙箱来测试:https://codesandbox.io/s/optimistic-tharp-czlgp?file=/src/App.js:124-601

【讨论】:

  • 这非常有效。我认为就像@Pawel Laskowski 所说的那样,问题是当我单击复选框时会触发两个事件。第一个事件切换复选框,第二个事件将其切换回来,这就是为什么我们认为它没有发生任何事情。并且您指定输入元素上的 onChange 所包含的第二个事件的解决方案不起作用onChange={ ev =&gt; {} }
【解决方案3】:

当您点击复选框时,您的点击事件会被 div 和 div 内的复选框同时传播和处理,这会导致状态被切换两次并最终具有与之前相同的值。

您需要删除其中一个 onClick,具体取决于您希望可点击的内容(整个 div 或只是带有标签的复选框)。

可点击的 div:

const Tile = ({ title }) => {
  const [selected, setSelected] = useState(false);
  useEffect(() => {
    console.log(selected)
  }, [selected])
  return (
    <>
      <div className="tile" onClick={() => setSelected(curr => !curr)}>
        <label>{title}</label>
        <input
          type="checkbox"
          checked={!!selected}
        />
      </div>
    </>
  );
};

可点击的复选框和标签:

const Tile = ({ title }) => {
  const [selected, setSelected] = useState(false);
  useEffect(() => {
    console.log(selected)
  }, [selected])
  return (
    <>
      <div className="tile">
        <label htmlFor="title">{title}</label>
        <input
          id="title"
          type="checkbox"
          checked={!!selected}
          onChange={() => setSelected(curr => !curr)}
        />
      </div>
    </>
  );
};

【讨论】:

  • 我认为这可能是我的问题的解决方案。请您详细说明我该怎么做。我尝试了 event.stopImediatePropagation 但无济于事
  • 如果你想让整个 div 都可以点击,只需从input 中删除 onChange。如果您只希望复选框及其标签可点击,请从 div 中删除 onChange 并将 htmlFor={title} 添加到 label。我会更新答案。
  • 感谢这项工作,但是从输入中删除 onChange 会引发警告 Warning: You provided a checked prop to a form field without an onChange handler. This will render a read-only field. If the field should be mutable use defaultChecked. Otherwise, set either onChange or readOnly. 我更喜欢用一个什么都不做的函数填充 onChange onChange={ev=&gt;{}}
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-13
  • 1970-01-01
相关资源
最近更新 更多