如何在React中使用useState检查复选框的更改值

时间:2019-10-23 22:48:16

标签: javascript reactjs

我将带有属性的复选框字段的列表传递给我的组件,我想根据人员的选择更改checked属性的值,但是我最大能做的就是将数组。

如何在我的状态下更改此特定密钥?

这是我的代码:

export default function Combocheck({ data, title, id }) {
  const inputLabel = React.useRef(null);

  const [state, setState] = React.useState({
    checkbox: data.map((element) => {
      element.checked = false;
      return element;
    })
  });

  const changeState = name => event => {
    const newValue = !state.checkbox[name].checked;
    setState({ checkbox: [
        ...state.checkbox,
        state.checkbox[name] = {
          ...state.checkbox[name],
          checked: newValue
        }
      ]
    });
  }

  console.log(state);

  return (
    <div> 
      <Typography color='textSecondary'>{title}</Typography>
      <Divider />
      <FormGroup>
        {state.checkbox.map(({code, description, checked}, i) => {
          return <FormControlLabel control={
            <Checkbox
              key={code}
              checked={checked}
              onChange={changeState(i)}
              value={code}
              color="primary"
            />
          }
          key={code}
          label={description}
          />
        })}
      </FormGroup>
    </div>
  );
}

可以在此处查看或编辑:https://stackblitz.com/edit/react-irhqw9?file=Hello.js

2 个答案:

答案 0 :(得分:3)

每次更新状态时,您都会添加一个复选框项!相反,请考虑在您的元素上进行映射,并仅更改适用的元素:

const changeState = name => event => {
  setState({ 
    checkbox: state.checkbox.map((checkbox, i) => {
      return i !== name ? 
        checkbox : 
        { ...checkbox, checked: !checkbox.checked }
    }) 
  });
}

我也不喜欢使用元素索引作为名称;我很确定您可以使用该代码(假设它是唯一的)就可以了,那么这不必是高阶函数:

const changeState = event => {
  setState({ 
    checkbox: state.checkbox.map((checkbox) => {
      return event.target.value !== checkbox.code ? 
        checkbox : 
        { ...checkbox, checked: !checkbox.checked }
    }) 
  });
}

,然后在Checkbox道具中:

onChange={changeState}

答案 1 :(得分:1)

我更喜欢为每个复选框使用一个useState函数。

在挂钩之前的“过去”时代,每个组件只有一个状态-setState函数会将状态与传递给setState的对象合并。 Hooks和useState并非那样。一个组件中可以有许多useState挂钩,并且状态不会合并。

有些代码可以粘贴到使用create-react-app创建的App.js中,以显示我的意思:

App.js

import React, { useState } from 'react';

function App() {
  var [ firstCheckbox, setFirstCheckbox ]   = useState(true); // true - first check box defaults to checked.
  var [ secondCheckbox, setSecondCheckbox ] = useState(false); // false = second check box defaults to un-checked.
  return (
    <div style={{display:'flex', flexDirection: 'column'}}>
        <label for='first-check-box'><input type="checkbox" checked={firstCheckbox} onChange={() => setFirstCheckbox(!firstCheckbox)}></input>First Check Box</label>
        <label for='second-check-box'><input type="checkbox" checked={secondCheckbox} onChange={() => setSecondCheckbox(!secondCheckbox)}></input>Second Check Box</label>
    </div>
  );
}

export default App;

另一个使chrome开发人员工具更有用的提示: 当您按照我的建议使用许多useState挂钩时,很难看到哪个状态挂钩是哪个。每个useState挂钩仅显示为useState: true,没有任何标签。下面的代码通过将实际状态设为对象的属性,并在chrome开发人员工具中显示标签,来标识开发人员工具的“组件”标签中的useState钩子。

App.js:

import React, { useState } from 'react';

function App() {
  var [ firstCheckbox, setFirstCheckbox ]   = useState({firstCheckBox: true});
  var [ secondCheckbox, setSecondCheckbox ] = useState({secondCheckBox: false});
  return (
    <div style={{display:'flex', flexDirection: 'column'}}>
        <label htmlFor='first-check-box'>
            <input type="checkbox"
                checked={firstCheckbox.firstCheckBox}
                onChange={() => setFirstCheckbox(
                    {firstCheckBox: !firstCheckbox.firstCheckBox}
                )}>
            </input>
            First Check Box
        </label>
        <label htmlFor='second-check-box'>
            <input
                type="checkbox"
                checked={secondCheckbox.secondCheckBox}
                onChange={() => setSecondCheckbox(
                    {secondCheckBox: !secondCheckbox.secondCheckBox}
                )}>
            </input>
            Second Check Box
        </label>
    </div>
  );
}

export default App;

为了清楚起见,我在上面使用了输入元素的onChange事件。这要求用户单击实际的复选框。我更愿意允许他们单击标签或复选框上的任何位置。为此,我们可以使用label元素的onClick事件:

为了避免在控制台中抱怨输入不是控制器,我也将它们标记为readOnly。

App.js:

import React, { useState } from 'react';

function App() {
  var [ firstCheckbox, setFirstCheckbox ]   = useState({firstCheckBox: true});
  var [ secondCheckbox, setSecondCheckbox ] = useState({secondCheckBox: false});
  return (
    <div style={{display:'flex', flexDirection: 'column'}}>
        <label
            htmlFor='first-check-box'
            onClick={() => setFirstCheckbox({firstCheckBox: !firstCheckbox.firstCheckBox})}>
            <input type="checkbox" checked={firstCheckbox.firstCheckBox} readOnly/>
            First Check Box
        </label>
        <label
            htmlFor='second-check-box'
            onClick={() => setSecondCheckbox({secondCheckBox: !secondCheckbox.secondCheckBox})}>
            <input type="checkbox" checked={secondCheckbox.secondCheckBox} readOnly/>
            Second Check Box
        </label>
    </div>
  );
}

export default App;