#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. Мне пришлось немного подправить, но в итоге все получилось идеально. простое и интуитивно понятное решение, но я был зациклен на том, чтобы попытаться сделать его рекурсивной функцией над возвратом компонента и реализовать ее в разделе возврата компонентов, поэтому я даже не рассматривал это решение, чтобы переместить его и просто вызвать компонент, когда условие было выполнено. все равно мне пришлось немного подправить его, но в конечном итоге это решило большую часть проблемы, и теперь у меня есть общая форма, в которую я могу бросить любой объект. спасибо за вашу помощь !