Рекурсия в компоненте react, который генерирует форму

#javascript #reactjs #typescript #forms #recursion

Вопрос:

Привет всем, ТАК ЧТО!

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

То есть до тех пор, пока я не доберусь до вложенного объекта.


Проблема:

Как только я нажму условие if (typeof value === "object") , я хочу иметь скрытый ввод (это работает).
Затем я хочу перейти к тому объекту, который я только что идентифицировал, и ко всем дочерним объектам, которые он может содержать, и сгенерировать входные данные по тем же критериям, что и при первоначальном прогоне.

 function GenericForm(props: any) {  var object = props.object;   return (  lt;divgt;  lt;formgt;  {Object.entries(object).map(([property, value]) =gt; {  let type: string = "";  if (typeof value === "string") {  type = "text";  } else if (typeof value === "number") {  type = "number";  } else if (typeof value === "boolean") {  type = "checkbox";  } else if (value instanceof Date) {  type = "date";  } else if (typeof value === "object") {  type = "hidden";  }   return [  lt;label property={property} htmlFor={property}gt;  {property}  lt;/labelgt;,  lt;input  type={type}  id={property}  name={property}  defaultValue={value as string}  onChange={(newVal) =gt; {  object[property] = newVal.target.value;  }}  /gt;,  ];  })}  lt;/formgt;  lt;/divgt;  ); } export default GenericForm;  

Я знаю, что это, скорее всего, использует какую-то рекурсию, и хотя я пытался решить ее с помощью рекурсии, я не смог ее решить.
код, вставленный сюда, был написан до того, как я попробовал рекурсию, чтобы получить «чистый лист» с того места, где у меня все пошло не так.

ПРАВКА 1 — добавлена информация о структуре объекта

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

один из текущих объектов, которые я передаю, имеет следующую схему JSON

 {  "id": "XYZ1",  "type": "twilio-api",  "sid": "someSID",  "from": " phonenumberhere",  "name": "TWILIO SMS",  "credentials": {  "token": "someapitoken"  } }  

вышеуказанный объект в настоящее время отображается следующим образом:

введите описание изображения здесь

Комментарии:

1. Можете ли вы также поделиться тем, как object это выглядит (вместе с ожидаемым результатом для этого)?

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

3. @NickParsons добавил правку в сообщение о схеме объекта. ожидаемым результатом будет метка учетных данных со скрытым вводом, а затем под маркером с его вводом, определенным типом, как и в предыдущем случае, это должно идти до конца структуры объекта, не ограничиваясь объектами «2 уровня» в связанном объекте

4. @T. J. Crowder поскольку английский не мой родной язык, я прошу прощения за любые ошибки в написании, которые я делаю, я использую свою автокоррекцию, чтобы исправить их перед публикацией, поэтому я надеюсь, что это не так уж плохо. попался на удочку, я соответствующим образом обновлю свой пост 🙂

5. @robskaar — 🙂 Я гарантирую вам, что вы пишете по-английски лучше, чем я пишу на любом другом языке. Одна вещь, которая действительно бросается в глаза носителям языка, заключается в том, что «Я» всегда пишется с заглавной буквы, а не в нижнем регистре (не «я»). Счастливого кодирования!

Ответ №1:

Предполагая, что у вас есть Input компонент:

 function Input = ({ name, type, value }) =gt; {  // most of your code can fit here  return lt;input name={name} type={type} value={value} /gt;  }  

Вы можете использовать свою версию кода, я использую упрощенную версию, как указано выше, чтобы облегчить наше обсуждение. С помощью этого мы можем спроектировать InputList компонент:

 function InputList = ({ object }) =gt; {  console.log('list', object)  return (  lt;divgt;  {Object.entries(object).map(([property, value]) =gt; {  if (typeof value === "object") {  return lt;InputList object={value} /gt;  } else {  return lt;Input name={property} /gt;  }  })}  lt;/divgt;  )  }  

Вы можете видеть внутри этого InputList , есть вызов InputList снова, так что это та рекурсия, которую вы ищете. Рекурсия прекращается, когда внутри объекта больше нет объекта.

ПРИМЕЧАНИЕ: React требует value и onChange для управления любой input коробкой. В противном случае они будут просто вести себя как собственный ввод. Но это не входит в этот вопрос.

Комментарии:

1. Спасибо за ответ, это кажется почти слишком простым и все же настолько очевидным, что я просто возвращаю другой компонент, если условие выполнено. Я сейчас как раз ухожу с работы. попробую это как-нибудь завтра, если это устранит проблему, я, конечно, отмечу это как ответ, а пока я поддержал ваше предложение, поскольку оно уже кажется интуитивно понятным 🙂

2. Это не проблема, @robskaar, есть несколько разных способов выполнения рекурсии. В более хрестоматийной версии мы бы разработали только один компонент под названием Input , но я нашел его слишком запутанным , когда дело доходит до тестирования. Лучше, чтобы мы могли видеть, как работает каждый простой ввод, а затем список входных данных, шаг за шагом.

3. Мне пришлось немного подправить, но в итоге все получилось идеально. простое и интуитивно понятное решение, но я был зациклен на том, чтобы попытаться сделать его рекурсивной функцией над возвратом компонента и реализовать ее в разделе возврата компонентов, поэтому я даже не рассматривал это решение, чтобы переместить его и просто вызвать компонент, когда условие было выполнено. все равно мне пришлось немного подправить его, но в конечном итоге это решило большую часть проблемы, и теперь у меня есть общая форма, в которую я могу бросить любой объект. спасибо за вашу помощь !