如何使用React钩子实现多个复选框

时间:2019-05-23 10:16:08

标签: javascript reactjs checkbox react-hooks

我想使用react-hook在HTML页面上实现多个复选框。

我尝试使用以下URL实施:https://medium.com/@Zh0uzi/my-concerns-with-react-hooks-6afda0acc672。在提供的链接中,它是使用类组件完成的并且可以正常工作,但是每当我使用React钩子setCheckedItems更新复选框选中状态时,它都不会重新呈现视图。

第一次渲染视图,并且从Checkbox组件打印console.log()。单击复选框功能后,将调用 handleChange 函数,并 checkedItems 更新该值,但视图不会再次呈现(不打印console.log())。并且 {checkedItems.get(“ check-box-1”)} 也不打印任何值。

下面是我的示例代码。

复选框示例

import React, { useState } from 'react';
import Checkbox from '../helper/Checkbox';

const CheckboxExample = () => {
    const [checkedItems, setCheckedItems] = useState(new Map());

    const handleChange = (event) => {
        setCheckedItems(checkedItems => checkedItems.set(event.target.name, event.target.checked));
        console.log("checkedItems: ", checkedItems);
    }

    const checkboxes = [
        {
            name: 'check-box-1',
            key: 'checkBox1',
            label: 'Check Box 1',
        },
        {
            name: 'check-box-2',
            key: 'checkBox2',
            label: 'Check Box 2',
        }
    ];


    return (
        <div>
            <lable>Checked item name : {checkedItems.get("check-box-1")} </lable> <br/>
            {
                checkboxes.map(item => (
                    <label key={item.key}>
                        {item.name}
                        <Checkbox name={item.name} checked={checkedItems.get(item.name)} onChange={handleChange} />
                    </label>
                ))
            }
        </div>
    );
}
export default Example;

复选框

import React from 'react';

const Checkbox = ({ type = 'checkbox', name, checked = false, onChange }) => {
    console.log("Checkbox: ", name, checked);

  return (<input type={type} name={name} checked={checked} onChange={onChange} /> )
}
export default Checkbox;

4 个答案:

答案 0 :(得分:2)

我认为最好不要使用Map来表示状态。
我已经使用普通的Object实现了您的示例,并且可以正常工作:

https://codesandbox.io/s/react-hooks-usestate-xzvq5

const CheckboxExample = () => {
  const [checkedItems, setCheckedItems] = useState({}); //plain object as state

  const handleChange = (event) => {
      // updating an object instead of a Map
      setCheckedItems({...checkedItems, [event.target.name] : event.target.checked });
      console.log("checkedItems: ", checkedItems);
  }

  const checkboxes = [
      {
          name: 'check-box-1',
          key: 'checkBox1',
          label: 'Check Box 1',
      },
      {
          name: 'check-box-2',
          key: 'checkBox2',
          label: 'Check Box 2',
      }
  ];


  return (
      <div>
          <lable>Checked item name : {checkedItems["check-box-1"]} </lable> <br/>
          {
              checkboxes.map(item => (
                  <label key={item.key}>
                      {item.name}
                      <Checkbox name={item.name} checked={checkedItems[item.name]} onChange={handleChange} />
                  </label>
              ))
          }
      </div>
  );
}

编辑:

结果证明Map可以作为状态值,但是要触发重新渲染,您需要用一个新的Map替换该Map,而不是简单地对其进行突变,这不是React所选择的,即:

const handleChange = (event) => {
  // mutate the current Map
  checkedItems.set(event.target.name, event.target.checked)
  // update the state by creating a new Map
  setCheckedItems(new Map(checkedItems) );
  console.log("checkedItems: ", checkedItems);
}

但是在这种情况下,我认为使用Map除了使用.get().set()而不是x[y]的语法更简洁以外,没有其他好处。

答案 1 :(得分:0)

似乎还有很长的路要走,但是如果您将地图展开并将其应用于new Map,则组件将重新渲染。我认为在这里使用对象引用代替Map效果最好。

const {useState} = React

const Mapper = () => {
  const [map, setMap] = useState(new Map());

  const addToMap = () => {
    const RNDM = Math.random().toFixed(5)
    map.set(`foo${RNDM}`, `bar${RNDM}`);
    setMap(new Map([...map]));
  }

  return (
    <div>
      <ul>
        {[...map].map(([v, k]) => (
          <li key={k}>
            {k} : {v}
          </li>
        ))}
      </ul>
      <button onClick={addToMap}>add to map</button>
    </div>
  );
};

const rootElement = document.getElementById("react");
ReactDOM.render(<Mapper />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>

答案 2 :(得分:0)

作为使用单个对象保存多个项目状态的补充,如果在单个渲染器中更新多个项目,更新将不会按预期进行。在渲染周期内,较新的提交将很简单覆盖以前的提交。

解决方案是将所有更改汇总到一个对象中,然后一次提交所有更改,如下所示:

// An object that will hold multiple states
const [myStates, setMyStates] = useState({});

// An object that will batch all the desired updates
const statesUpdates = {};

// Set all the updates...
statesUpdates[state1] = true;
statesUpdates[state2] = false;
// etc...

// Create a new state object and commit it
setMyStates(Object.assign({}, myStates, statesUpdates));

答案 3 :(得分:0)


export default function Input(props) {
    const {
        name,
        isChecked,
        onChange,
        index,
    } = props;

    return (
        <>
            <input
                className="popup-cookie__input"
                id={name}
                type="checkbox"
                name={name}
                checked={isChecked}
                onChange={onChange}
                data-action={index}
            />
            <label htmlFor={name} className="popup-cookie__label">{name}</label>
        </>
    );
}

const checkboxesList = [
    {name: 'essential', isChecked: true},
    {name: 'statistics', isChecked: false},
    {name: 'advertising', isChecked: false},
];

export default function CheckboxesList() {
    const [checkedItems, setCheckedItems] = useState(checkboxesList);

    const handleChange = (event) => {
        const newCheckboxes = [...checkedItems];
        newCheckboxes[event.target.dataset.action].isChecked = event.target.checked;
        setCheckedItems(newCheckboxes);
        console.log('checkedItems: ', checkedItems);
    };

    return (
        <ul className="popup-cookie-checkbox-list">
            {checkboxesList.map((checkbox, index) => (
                <li className="popup-cookie-checkbox-list__item" key={checkbox.name}>
                    <Input
                        id={checkbox.name}
                        name={checkbox.name}
                        isChecked={checkbox.isChecked}
                        onChange={handleChange}
                        index={index}
                    />
                </li>
            ))}
        </ul>
    );
}```