0

我目前有一个带有标题的页面:h1、h2、h3。我希望他们的文本可以由用户 onClick 编辑,所以基本上标题将变成 input type='text' 然后当用户在输入中输入他的值时恢复到标题。我使用 useReducer 钩子让这个功能工作得很好,我在其中调度了与每个相关的相应值。但是,我正在努力弄清楚如何使 textIsEditing prop/boolean 可在所有 3 个组件中重复使用。让我用代码解释一下:

JSON数据:

{
  "name":"Click to rename One",
  "campaigntype": "Click to rename Two",
  "description": "Click to rename Three",
}

包含 3 个标头的组件:

export default function MetaData() {
  const [nameIsEditing, setNameEditing] = useState(false);
  const [campaignIsEditing, setCampaignIsEditing] = useState(false);
  const [descriptionIsEditing, setDescriptionIsEditing] = useState(false);

  function toggleNameEdit(){
    setNameEditing(!nameIsEditing);
  }
  function toggleCampaignEdit(){
    setCampaignIsEditing(!campaignIsEditing);
  }
  function toggleDescriptionEdit(){
    setDescriptionIsEditing(!descriptionIsEditing);
  }

  const initialState = jsonData;

  const [metaData, dispatch] = useReducer(metaDataReducer, initialState);

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const defaultMetaValue = metaData[e.target.name as keyof MetaState];

    dispatch({ type: e.target.name, value: e.target.value === '' ? defaultMetaValue : e.target.value });
  };

  return (
    <Grid className='menuItem' container direction='column'>

      {nameIsEditing ?
        <RenameInput name='name' textStyle='h3' onClickAway={toggleNameEdit} onSubmit={toggleNameEdit} adName={metaData.name} onChange={handleChange} />
        :
        <H1 onClick={toggleNameEdit}>{metaData.name}</H1>}

      {campaignIsEditing ?
        <RenameInput name='campaigntype' textStyle='subtitle2' onClickAway={toggleCampaignEdit} onSubmit={toggleCampaignEdit} campaignType={metaData.campaigntype} onChange={handleChange} />
        :
        <H2 onClick={toggleCampaignEdit}>{metaData.campaigntype}</H2>}

      {descriptionIsEditing ?
        <RenameInput paragraph textStyle='body2' name='description' onClickAway={toggleDescriptionEdit} onSubmit={toggleDescriptionEdit} adDescription={metaData.description} onChange={handleChange} />
        :
        <H3 onClick={toggleDescriptionEdit} className='meta-description'>{metaData.description}</H3>}

    </Grid>);
}

减速机:

const metaDataReducer = (state: MetaState, action: ActionType) => {

  if (action.type in state) {
    return { ...state, [action.type]: action.value };
  } else {
    return state;
  }

};

重命名输入:

const RenameInput = (props) => {
  return (
    <ClickAwayListener onClickAway={props.onClickAway}>
      <form onSubmit={props.onSubmit}>
        <TextInput
          defaultValue={props.adName || props.adDescription || props.campaignType}
          autoFocus
          onChange={props.onChange}
          multiline={props.paragraph}
          textStyle={props.textStyle}
          name={props.name}
        />
      </form>
    </ClickAwayListener>
  );
};

在我的 MetaData 组件上,我真的不喜欢这部分代码

 const [nameIsEditing, setNameEditing] = useState(false);
  const [campaignIsEditing, setCampaignIsEditing] = useState(false);
  const [descriptionIsEditing, setDescriptionIsEditing] = useState(false);

  function toggleNameEdit(){
    setNameEditing(!nameIsEditing);
  }
  function toggleCampaignEdit(){
    setCampaignIsEditing(!campaignIsEditing);
  }
  function toggleDescriptionEdit(){
    setDescriptionIsEditing(!descriptionIsEditing);
  }

我想让它在所有 3 个组件中重复使用,因为它实际上在做同样的事情。我需要一个函数来处理所有这三个,但我真的不确定在哪里或如何做到这一点?我是在减速器中执行此操作,还是如何将其转换为工厂功能?一定有比我做的更好的方法{nameIsEditing ? renameComponent : h1 {campaignIsEditing ? renameComponent : h2 {descriptionIsEditing ? renameComponent : h3

4

1 回答 1

1

您应该简单地创建一个新组件EditableTitle。它将处理isEditing状态,并执行呈现只读标题或RenameInput组件的逻辑。
为了处理标题之间的微小差异,您可以将道具发送到EditableTitle. 例如,您可以发送一个component值来呈现一个h1、一个h2或任何其他您想要的组件。

于 2020-06-08T22:36:58.720 回答