Динамически вложенные компоненты React

Я использую приведенный ниже код, и он выполняет свою работу (на данный момент). В зависимости от длины массива компоненты вкладываются друг в друга со ссылкой на элемент массива в качестве опоры. Внутри самого внутреннего элемента всегда должен быть вставлен другой элемент.

const arr = ['one', 'two', 'three'];
const injectedContent = <SomeContent />;

const renderNestedSections = () => {
  switch (arr.length) {
    case 1:
      return (
        <Section name = {arr[0]}>
          {injectedContent}
        <Section>
      );

    case 2:
      return (
        <Section name = {arr[0]}>
          <Section name = {arr[1]}>
            {injectedContent}
          </Section>
        </Section>
      );

    case 3:
      return (
        <Section name = {arr[0]}>
          <Section name = {arr[1]}>
            <Section name = {arr[2]}>
              {injectedContent}
            </Section>
          </Section>
        </Section>
      );

    default:
      return null;
  }
}

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

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
0
888
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

Вот что-то не в моей голове. Возможно, есть лучший / более ясный способ сделать это, но идея состоит в том, что вы перебираете каждый элемент в массиве и строите его наружу, оборачивая каждый раздел внутри другого раздела.

Для этого используется Array#reduce, начиная со значения аккумулятора вашего внедренного контента. Затем вы просто строите вверх по направлению к самой внешней секции. Кроме того, поскольку мы строим наружу, а не внутрь, мы должны перевернуть массив (имейте в виду, что это приведет к изменению массива, поэтому вы можете захотеть клонировать его, прежде чем делать это).

Вот доказательство концепции с использованием DOM, а не React.

let arr = ['one', 'two', 'three']
// Inner Content
let content = document.createElement('div')
content.innerHTML = "Hello World"

// Algorithm
let res = arr.reverse().reduce((acc, item)=>{
  let a = document.createElement('div')
  a.classList.add(item)
  a.appendChild(acc)
  return a
}, content)

document.body.appendChild(res)
div {
  padding : 10px;
  color : white;
}

.one {
  background-color: red;
}
.two {
  background-color: green;
}
.three {
  background-color: blue;
}

Вот как, я думаю, будет выглядеть версия React, но я ее не тестировал.

const arr = ['one', 'two', 'three'];
const injectedContent = <SomeContent />;

// Algorithm
let result = arr.reverse().reduce((acc, item)=>{
  return (
    <Section name = {item}>
      {acc}
    </Section>
  )
}, InjectedContent)

Я протестировал его, и он отлично работает. Очень компактное решение, еще раз спасибо!

ibechev 16.06.2018 20:46

Вы можете использовать рекурсивный подход к рендерингу, например

const arr = ["one", "two", "three", "four"];
const injectedContent = () => <SomeContent />;

const Section = ({ name, children }) => (
  <div>
    <div>{name}</div>
    {children}
  </div>
);

const SomeContent = () => <div>Some Content</div>;

const RecursiveContent = ({ InjectedContent, arr }) => {
  const name = arr[0];

  return (
    <Section arr = {arr} name = {name}>
      {arr.length > 0 ? (
        <RecursiveContent arr = {arr.slice(1)} InjectedContent = {InjectedContent} />
      ) : (
        <InjectedContent />
      )}
    </Section>
  );
};
const NestedSection = InjectedContent => ({ arr }) => (
  <RecursiveContent arr = {arr} InjectedContent = {InjectedContent} />
);

function App() {
  return (
    <div className = "App">
      <NestedEle arr = {arr} />
    </div>
  );
}

const NestedEle = NestedSection(injectedContent);

Рабочая песочница

это компонент реакции рекурсивный и декларативный:

const RecursiveNodeWrapper = ({ layers, node }) => {
  let accumulatedNode = node;
  if (layers.length) {
    const [currentLayer, ...restLayers] = layers;
    accumulatedNode = (
      <section style = {{ border: '1px solid', padding: 5 }} name = {currentLayer}>
        {accumulatedNode}
      </section>
    );
    return RecursiveNodeWrapper({
      layers: restLayers,
      node: accumulatedNode,
    });
  }
  return accumulatedNode;
};

тогда вам просто нужно вызвать его как обычный компонент:

<RecursiveNodeWrapper layers = {['one', 'two']} node = {<h1>hello</h1>} />

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