有效地更新React useState对象

时间:2020-09-11 04:41:59

标签: reactjs material-ui

我正在使用Material UI Accordian(来自文档的受控示例),并且我希望默认情况下打开所有面板。我已经能够通过创建如下状态对象来实现这一点。但是,我认为我用于更新handleChange上状态的方法很笨拙。

有没有更好的方法来写这个?

  const [state, setstate] = useState({
    panel1: true,
    panel2: true,
    panel3: true,
    panel4: true,
  });

  const handleChange = (panel: string) => (event: React.ChangeEvent<{}>, isExpanded: boolean) => {
    switch (panel) {
      case "panel1":
        setstate({ ...state, panel1: state.panel1 ? false : true });
        break;
      case "panel2":
        setstate({ ...state, panel2: state.panel2 ? false : true });
        break;
      case "panel3":
        setstate({ ...state, panel3: state.panel3 ? false : true });
        break;
      case "panel4":
        setstate({ ...state, panel4: state.panel4 ? false : true });
        break;
      default:
        break;
    }
  };

3 个答案:

答案 0 :(得分:0)

改为使用数组:

const [panels, setPanels] = useState(new Array(4).fill(true));
const handleChange = (panelIndex: number) => () => {
  const newPanels = [...panels];
  newPanels[panelIndex] = !newPanels[panelIndex];
  setPanels(newPanels);
};

然后使用例如handleChange(0)handleChange(2)代替handleChange('panel1')handleChange('panel3')

答案 1 :(得分:0)

您可以这样操作,其中panel in state代替了default中的switch..case

const [state, setstate] = useState({
  panel1: true,
  panel2: true,
  panel3: true,
  panel4: true
})

const handleChange = (panel: string) => (
  event: React.ChangeEvent<{}>,
  isExpanded: boolean
) => {
  panel in state &&
    setstate(prevState => ({
      ...prevState,
      [panel]: state[panel] ? false : true
    }))
}

答案 2 :(得分:0)

如果仅将“受控”模式用于切换打开/关闭,则可以将默认的手风琴扩展到新组件。将打开/关闭状态恢复为自己的状态。

const NewAccordion = ({ initialOpen = true, ...restProps }) => {
    const [expanded, setExpanded] = React.useState(initialOpen)
    const toggle = (event, isExpaneded) => setOpened(!isExpaneded)
    return (
        <Accordion expanded={expaneded} onChange={toggle} {...restProps} />
    )
}

如果仍然要使用对象,则只需覆盖当前面板的状态即可。无需使用开关盒

const [state, setState] = React.useState({
    panel1: true,
    panel2: true
})
const handleChange = (panel) => (event, isExpaneded) => setState(prev => ({ ...prev, [panel]: !isExpaneded }))

// render
<Accordion expaneded={state.panel1} onChange={handleChange('panel1')} />