反应状态中的许多布尔属性 - 如何重构?

Many boolean properties in react state - how to refactor?

我有一个 React 组件,它是一个包含许多按钮的报告。您可以通过单击 table 行或单击按钮打开一些子报表。我为每个报告保留状态布尔值。基本上我的类型状态接口是这样的:

interface State {
  isSubreportVisible: boolean;
  isLogsVisible: boolean;
  isSelectStatusVisible: boolean;
  isMoneyVisible: boolean;
  isTargetStoreWarningVisible: boolean;
  isMultiVisible: boolean;
  isCancelVisible: boolean;
  isPrintVisible: boolean;
}

那么我的初始状态是这样的:

public state: State = {
  isSubreportVisible: false,
  isLogsVisible: false,
  isSelectStatusVisible: false,
  isMoneyVisible: false,
  isMultiVisible: false,
  isTargetStoreWarningVisible: false,
  isCancelVisible: false,
  isPrintVisible: false,
};

内部组件我有:

{isSubreportVisible && (
  <Subreport
    ...
    ...
    ...
  />
)}

组件的文件很长——将近600行代码。这里有什么可以做的吗?模态中的所有子报表都连接到这个组件? 创建一个名为 "types.tsx" 的文件并将所有接口(State、StateToProps、Props 等)移到那里是否是一个好的模式?有任何想法吗?也许在状态中只有一个字符串值 - currentModalVisible 并保留其名称来自枚举会更好?

Maybe it could be better to have just one string value in state - currentModalVisible and to keep there its names from enum?

这取决于 -- 一次只能看到一个模式吗?如果是这样,那么我将存储一个值,它是 null/undefined 或可见模态的名称。如果模式独立切换,那么您将需要为每个模式存储一个 boolean

无论哪种方式,我认为这里的一个很好的目标是拥有将模态的 string 键作为参数的通用函数。您希望能够调用 isModalVisible('print')toggleModalVisible('print')setModalVisible('print', false)

我会为 modals/subreports 可用的道具定义一个 type。您希望组件不能需要任何额外的道具。这样你就可以通过它的变量调用一个组件并将所有可用的道具传递给它一些将被忽略)。

为了获得最大的灵活性,您甚至可以将可用的模态作为 prop 传递。

interface ModalProps {
  someKey: string;
}

interface FlexibleSettings {
  // what to display in your tab/toggle
  // optional because can default to a cased version of the `key`
  buttonText?: React.ReactNode;
  // the component to render when selected
  modal: React.ComponentType<ModalProps>;
}

interface VeryFlexibleComponentProps<Keys extends string> {
  // pass the modals as an object keyed by the modal key
  modals: Record<Keys, FlexibleSettings>;
  // can start with one visible
  initialVisible?: Keys;
  // need to access the ModalProps somewhere
  // maybe some come from this component and can be omitted
  modalProps: ModalProps;
}

const VeryFlexibleComponent = <Keys extends string>({
  modals,
  initialVisible,
  modalProps
}: VeryFlexibleComponentProps<Keys>) => {
  const [visible, setVisible] = React.useState(initialVisible); // type Keys | undefined

  // need an uppercase variable to call a component with JSX
  const CurrentModal = visible ? modals[visible].modal : undefined;

  return (
    <div>
      <h3>Select Modal</h3>
      {(Object.keys(modals) as Keys[]).map((key) => (
        <div key={key}>
          <input
            type="radio"
            name="visible"
            value={key}
            id={key}
            checked={visible === key}
            onChange={(e) => {
              if (e.target.checked) setVisible(key);
            }}
          />
          <label htmlFor={key}>
            {modals[key].buttonText ?? _startCase(key)}
          </label>
        </div>
      ))}
      {CurrentModal !== undefined && (
        <div>
          <h3>Viewing Modal</h3>
          <CurrentModal {...modalProps} />
        </div>
      )}
    </div>
  );
};

Code Sandbox