#reactjs
#reactjs
Вопрос:
Спасибо, что нашли время прочитать это.
Я новичок в React и немного затрудняюсь с динамическим рендерингом компонентов. Объект, полученный из API, может быть произвольно вложен на x количество уровней, а имена компонентов, которые необходимо ввести, получены из BE.
Я получаю ответ от API, который выглядит примерно так :
{
name: 'div'
components: [
componentOne: {
name: 'div'
components: [
{
name: 'p',
components: [...deeply nested]
},
{
name: 'h1',
components: [...deeply nested]
}
]
}
componentTwo: {
name: 'nav',
components: [...]
}
]
}
Комментарии:
1. Привет, я чувствую, что здесь нет четкого вопроса. Можете ли вы подробнее описать, что вы хотите сделать, что вы пробовали и в чем была ваша проблема при попытке?
2. Привет @remix, в основном цель состоит в том, чтобы визуализировать компоненты на основе ответа API. Итак, из опубликованного примера мне нужно было бы визуализировать smtgh следующим образом:
<div> <p></p> <h1></h1> <div/> <nav></nav>
Основная проблема заключается в том, что я не могу знать, насколько глубокой будет вложенность, потому что пользователь имеет возможность создавать свой пользовательский интерфейс в CMS и добавлять столько компонентов, сколько он хочет, в любую структуру, которую он хочет. Таким образом, рекурсия была вариантом, но у меня возникла проблема с определением способа динамического внедрения компонентов как дочерних компонентов, которые были динамически введены. (Надеюсь, я не запутал вас еще больше)
Ответ №1:
Вам придется обрабатывать узлы другого типа (по крайней мере, текстовые), но это всего лишь вопрос перехода по дереву (ответ API) и построения дерева узлов React в соответствии с ним:
итак, ваше определение узла выглядит следующим образом (это псевдограмматика, и ее не должно быть в вашем коде):
node: {
type: 'element' | 'text' => the type will be needed,
name: string => a tag name (if it is a React element),
children: node[]
}
Таким образом, фактический ответ от вашего api может быть:
{
type: 'element',
name: 'div',
children: [
{
type: 'element',
name: 'div',
children: [
{
type: 'element',
name: 'h1',
children: [
{ type: 'text', value: 'Title 1' }
]
},
{
type: 'element',
name: 'p',
children: [
{ type: 'text', value: 'This is a paragraph' }
]
}
]
},
{
type: 'element',
name: 'nav',
children: []
}
]
}
Мы передадим этот ответ, проанализированный как объект, в метод generateTreeNode:
/**
* @param {object} apiResponse
* @returns {ReactNode}
*/
function generateTreeNode(apiResponse) {
switch (apiResponse.type) {
case 'element':
return React.createElement(apiResponse.name, { children: apiResponse.children.map(child => generateTreeNode(child)) });
case 'text':
return apiResponse.value;
default: // no default
}
}
Обратите внимание, что рекурсивный вызов гарантирует, что будет пройдено все дерево apiResponse.
Вот и все. Это непроверено, но должно работать довольно хорошо: возврат функции generateTreeNode может быть использован в качестве возвращаемого значения метода рендеринга.
Основные ресурсы, которые вы должны понимать, чтобы использовать это, — это что такое React Node и создание react node.
Кроме того, не стесняйтесь (и вам следует) расширять структуру ответа api и переходить к обработке:
- пользовательские компоненты (которые вам придется каким-то образом импортировать)
- дополнительные элементы реквизита (такой стиль или имена классов)
- и т.д…
Обратите также внимание, что этот код предполагает, что корнем вашего ответа является один узел (помните, как React не позволяет вам возвращать несколько узлов одновременно в методе рендеринга, отложив массив и фрагменты в сторону, вот почему)