Как сохранить значение выбранных флажков в динамической форме с помощью Zod?

Я использую zod для формы в приложении React. В форме есть текстовое поле поиска. Вы можете ввести ключевые слова поиска в это текстовое поле для поиска веб-сайтов, и результат поиска (название веб-сайтов) будет отображаться в виде флажков. Затем вы можете выбрать нужные веб-сайты, установив эти флажки. Я просто хочу сохранить URL-адрес проверенных веб-сайтов в массиве строк.

Обычно, когда вы используете флажок с zod, значение является логическим (отмечено или нет). Я не знаю, как хранить строковые данные (URL-адрес веб-сайта) из флажка. Кроме того, форма является динамической, поскольку если вы ищете, скажем, «спорт», вы получаете флажки для спортивных веб-сайтов. Если вы измените ключевые слова поиска на «новости», спортивные флажки будут заменены на «новостные» веб-сайты, но выбранные URL-адреса «спортивных» веб-сайтов должны быть где-то сохранены.

Здесь вы можете увидеть схему проверки zod, которую я использую.

const zodValidationSchema = z.object({
   zodSitesUrls: z.string()
     .array()
     .min(1, { message: "You must choose at least one web site" })
 });

Там вы можете видеть, что я использую карту для отображения флажков. Это работает нормально! Но Мне интересно, как сохранить URL-адрес веб-сайта...

{webSites?.map((ns, index) => (
              <Controller
                name = {`zodSitesUrls.${index}`}
                control = {control}
                render = {({ field }) =>
                  <Checkbox {...field}
                    label = {ns.siteName}
                    onChange = {(e, isChecked) => onChangeWebSite(e, isChecked, ns.siteUrl)}
                  />
                }
               />
      )}

Я мог бы использовать событие флажков onChange для выбранного URL-адреса веб-сайта, но я не знаю, как сохранить URL-адрес в схеме zod.

Если вы дадите мне какие-либо советы или предложения о том, как это сделать, я буду рад! Заранее большое спасибо!

Обновлено:

Я нашел часть решения. Вот что я нашел:

               <Controller
                name = {`zodNewsSitesUrls.${index}`}
                aria-describedby = {`newsSiteToolTip-${index}`}
                control = {control}
                render = {({ field }) =>
                  <Checkbox {...field}
                    className = {styles.newsSiteCheckbox}
                    label = {ns.siteName}
                    aria-describedby = {`newsSiteToolTip-${index}`}
                   !== -1}
                    onChange = {(e, isChecked) => {
                      field.onChange(isChecked ? ns.siteUrl : "");
                    }}
                  />
                }
              />

Я изменил метод onChange. Теперь я могу присвоить значение объекту zodSitesUrls. Проблема, с которой я все еще сталкиваюсь, заключается в том, что если я проверю, скажем, первый флажок, затем изменю ключевое слово поиска, а затем снова проверю первый флажок, первый элемент массива будет перезаписан, потому что первый объект любого результата поиска всегда имеет то же имя (zodNewsSitesUrls.${index}). Поэтому, когда результаты поиска изменяются, предыдущие результаты поиска забываются...

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
0
77
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема, с которой вы сталкиваетесь при моделировании, заключается в том, что вы предполагаете однозначное сопоставление между ссылкой на состояние формы (name) и входным «элементом управления» (флажком).

В вашем случае концептуальное сопоставление между флажком и состоянием формы, в котором он содержится, должно быть «многие к одному». Нет смысла сопоставлять отдельный флажок с его собственным адресуемым элементом состояния, поскольку состояние флажка на самом деле является просто функцией того, что присутствует и чего нет в zodSitesUrls. Если URL-адрес отсутствует, значит, ему просто нет соответствующей записи в zodSitesUrls. Таким образом, нет состояния для привязки «неотмеченного» флажка. Вот что приводит к проблемам, когда вы предполагаете, что между индексом массива и каждым флажком существует какое-то сопоставление. Такого стабильного отображения не существует.

Итак, мы можем подключить один контроллер к zodSitesUrls и несколько флажков внутри этого контроллера.

Мы переопределяем логику onChange, чтобы добавлять/удалять соответствующий URL-адрес zodSitesUrls в зависимости от того, отмечен он или нет.

Мы также переопределяем логику value, чтобы она показывалась отмеченной галочкой, если соответствующий URL-адрес присутствует в zodSitesUrls.

Вы не указали, из какой библиотеки Checkbox. Он может использовать что-то кроме value, чтобы контролировать, отмечен ли он. Из вашего исходного вопроса я предположил, что второй аргумент onChange действительно isChecked. То, как именно эти вещи связаны, зависит от библиотеки.

Кроме того, форма является динамической, поскольку если вы ищете, скажем, «спорт», вы получаете флажки для спортивных веб-сайтов. Если вы измените ключевые слова поиска на «новости», спортивные флажки будут заменены на «новостные» веб-сайты, но выбранные URL-адреса «спортивных» веб-сайтов должны быть где-то сохранены.

С этим решением все будет работать нормально. Если флажки внутри контроллера изменятся, это не имеет значения. Поскольку все извлекается из основного списка URL-адресов, и значение этого списка не нужно будет изменять при отображении различных флажков, оно будет независимо от этого.

Это означает, что вы можете отобразить набор флажков, заполнить список с их помощью, отобразить совершенно новый набор, еще больше заполнить список, вернуться к исходному набору и удалить некоторые элементы и т. д.

<Controller
  name = "zodSitesUrls"
  control = {control}
  render = {({ field }) =>
    webSites?.map((ns, index) => (
      <Checkbox
        key = {ns.siteUrl}
        label = {ns.siteName}
        {...field}
        
        // Override default field.onChange
        onChange = {(e, isChecked) => {
          // Checked case
          if (isChecked) {
            // Already in list, do nothing
            if (field.value.includes(ns.siteUrl)) return
            
            // Add entry to array, without losing existing entries
            field.onChange([...field.value, ns.siteUrl])
            
            return
          }
        
          // Unchecked case
          // Filter this value out from list (doesn't matter if it was never here anyway)
          field.onChange(field.value.filter(url => url !== ns.siteUrl))
        }}
        
        // Override default field.value
        value = {field.value.includes(ns.siteUrl)}
      />
    ))
  }
/>

Вам также следует убедиться в defaultValues конфигурации формы, что zodSitesUrls является массивом. Например. zodSitesUrls: [].

О, я думал, что у каждого контроллера может быть только один элемент управления! Спасибо большое, Адси! Ваше решение работает! И спасибо за ваше объяснение!

andré marquis 20.06.2024 16:26

Другие вопросы по теме