Абстрагирование React Hooks для динамических c полей формы - PullRequest
2 голосов
/ 28 января 2020

Я использую библиотеку реагирующий крючок для создания многошаговой динамической c большой формы (более 70 полей). Большинство полей моей формы являются динамическими c (пользователь может добавить / удалить больше полей, нажав кнопку +). Чтобы добиться этого, я использую реагирующие зацепки и добавляю зацепки для каждого поля Dynami c. Но я чувствую, что мой код недостаточно абстрактен, и, возможно, есть более разумный способ сделать это. Ниже приведен пример скриншота моей формы:

enter image description here

Соответствующий код для хуков и полей формы здесь:

         // hooks
         const [sizes, setSizes] = React.useState([0]);
         const [formats, setFormats] = React.useState([0]);

         const [counter, setCounter] = React.useState(1);

         // buttons
         const addSizesFieldset = () => {
         setSizes(prevIndexes => [...prevIndexes, counter]);
         setCounter(prevCounter => prevCounter + 1);
         };

         const removeSizesFieldset = index => () => {
         setSizes(prevIndexes => [
         ...prevIndexes.filter(item => item !== index)
         ]);
         setCounter(prevCounter => prevCounter - 1);
         };


         const addFormatsFieldset = () => {
         setFormats(prevIndexes => [...prevIndexes, counter]);
         setCounter(prevCounter => prevCounter + 1);
         };

         const removeFormatsFieldset = index => () => {
         setFormats(prevIndexes => [
         ...prevIndexes.filter(item => item !== index)
         ]);
         setCounter(prevCounter => prevCounter - 1);
         };


        // form field arrays
        {sizes.map(index => {
            const fieldName = `sizes[${index}]`;
            return (
                <fieldset name={fieldName} key={fieldName} >
                    <h4>Sizes:</h4>
                    <label>
                        Size:
                        <input
                            type="text"
                            placeholder="Input"
                            name={`${fieldName}.size`}
                            ref={register}

                        />
                    </label>

                    <button type="button" onClick={addSizesFieldset}>
                        +
                    </button>
                    <button type="button" onClick={removeSizesFieldset(index)}>
                        -
                    </button>
                </fieldset>
            );
        })}
            {formats.map(index => {
                const fieldName = `formats[${index}]`;
                return (
                    <fieldset name={fieldName} key={fieldName} >
                        <h4>Formats:</h4>
                        <label>
                            Format:
                            <input
                                type="text"
                                placeholder="Input"
                                name={`${fieldName}.format`}
                                ref={register}

                            />
                        </label>

                        <button type="button" onClick={addFormatsFieldset}>
                            +
                        </button>
                        <button type="button" onClick={removeFormatsFieldset(index)}>
                            -
                        </button>
                    </fieldset>
                );
            })} ´´

Представьте, что вы выполняете эти моменты хуков и const add/remove...Fieldset функции для семидесяти полей. Это показалось мне слишком большим дублированием, но я не смог найти никакого решения или новой идеи, кроме «React может обрабатывать несколько хуков, поэтому не стоит беспокоиться».

Если вы хотите попробовать свои идеи на codeandbox, я также подготовил следующий код:

https://codesandbox.io/s/react-hook-form-wizard-form-yzno5

Ответы [ 2 ]

2 голосов
/ 28 января 2020

Возможно, если вы используете useReducer, было бы лучше, если бы у вас было несколько состояний

Пример

const initialState = {
  counter: 1,
  sizes: [0],
  formats: [0],
};

function reducer(state, action) {
  switch (action.type) {
    case 'add':
      return {
        ...state,
        counter: state.counter + 1,
        [action.typeObject]: [...state.sizes, state.counter + 1]
      };
    case 'remove':
      return {
        ...state,
        counter: state.counter - 1,
        [action.typeObject]: [...state.sizes.filter(item => item !== action.index)]
      };
    default:
      return state;
  }
}

/***/

const [stateReducer, dispatch] = React.useReducer(reducer, initialState);

/***/

const addSizesFieldset = () => {
  dispatch({ type: 'add', typeObject: 'sizes' })
};

const removeSizesFieldset = index => () => {
  dispatch({ type: 'remove', typeObject: 'sizes', index })
};

const addFormatsFieldset = () => {
 dispatch({ type: 'add', typeObject: 'formats' })
};

const removeFormatsFieldset = index => () => {
  dispatch({ type: 'remove', typeObject: 'formats', index })
};

Проверьте это

Вот моя простая реализация: разветвление вашего кода: https://codesandbox.io/s/react-hook-form-wizard-form-1h4yq


Редактировать:

Вы даже можете удалить 2 функции, добавив «typeObject» в параметре:

const addFieldset = field => () => {
  dispatch({ type: 'add', typeObject: field })
};

const removeFieldset = (index, field) => () => {
  dispatch({ type: 'remove', typeObject: field, index })
};

1 голос
/ 30 января 2020

не рассматриваете ли вы использовать наш новый пользовательский крючок useFieldArray? возможно, это альтернативное решение для этих динамических c полей. Я не тестировал с динамическим c append, стоит попробовать. обратная связь приветствуется.

Вы также можете следить за вопросами в нашем канале спектра: https://spectrum.chat/react-hook-form?tab=posts

https://react-hook-form.com/api#useFieldArray

function App() {
  const { register, control, handleSubmit } = useForm({
    // defaultValues: {}; you can populate the fields by this attribute 
  });
  const { fields, append, prepend, remove } = useFieldArray({ control, name: "test" });

  return (
    <form onSubmit={handleSubmit(data => console.log("data", data))}>
      <ul>
        {fields.map((item, index) => (
          <li key={item.id}>
            {/* for empty validation register make sure pass empty object  */}
            <input name={`test[${index}].name`} ref={register({})} /> 
            <button onClick={() => remove(index)}>Delete</button>
          </li>
        )}
      </ul>
      <section>
        <button type="button" onClick={() => append({ name: "test" })} >
          append
        </button>
        <button type="button" onClick={() => prepend({ name: "test1" })}>
          prepend
        </button>
    </form>
  );
}
...