反应复选框未正确呈现

react check box not rendering correctly

我正在尝试创建一个代表图块的 React 组件。

这个组件只是一个 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 修复的问题是标签是可点击的,复选框是可点击的,但它们之间的 space 不是。我希望整个组件都可以点击

将 htmlFor prop 添加到标签并将 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>
    </>
  );
};

您的 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

当你点击复选框时,你的点击事件被 div 和 div 中的复选框传播和处理,这导致状态被切换两次并最终具有相同的状态值和以前一样。

您需要删除其中一个 onClicks,具体取决于您希望可点击的内容(整个 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>
    </>
  );
};