Реагировать — визуализировать динамические компоненты на основе ответа API

#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 не позволяет вам возвращать несколько узлов одновременно в методе рендеринга, отложив массив и фрагменты в сторону, вот почему)