React — текущее количество компонентов в дочерних элементах (например, для сносок)

У меня есть компонент реакции, который представляет документ с текстом и некоторыми сносками. Текст должен быть представлен следующим образом:

This the first footnote[1], this is the second[2].

Here is another [3].

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

Это также должно быть динамическим, чтобы добавление ссылок обновляло счетчик.

Я не могу придумать очень «реактивный» способ сделать это. Контекст (как бы он ни осуждался) не кажется правильным, и в противном случае у вас нет информации о соседних компонентах.


person Thariq Shihipar    schedule 22.05.2017    source источник
comment
Как выглядит ваша структура данных? Это похоже на то, что нужно разобраться с исходными данными, поэтому компоненты просто отображают то, что им дано.   -  person Aaron Beall    schedule 22.05.2017
comment
Я согласен, может быть, с предварительной обработкой самих данных. Я искал решение, похожее на React, чтобы мне не пришлось вручную просматривать дерево и обновлять все эти узлы.   -  person Thariq Shihipar    schedule 22.05.2017
comment
Вы сохраняете этот документ? Не становится ли это какой-то структурой данных? Разве вы не можете получить количество сносок из этого? Они добавляются динамически? Если это так, вы можете запустить событие вверх по иерархии DOM. Вы также можете использовать redux для хранения всех ваших сносок.   -  person Juan Mendes    schedule 22.05.2017


Ответы (1)


Я думаю, я бы справился с этим так...

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

const DocComponent = () => {
  const footnotes = [];
  return (
    <div>
       <SomeContent footnotes={footnotes} />
       <SomeOtherContent footnotes={footnotes} />
       <EvenDifferentContent footnotes={footnotes} />
       <Footnotes footnotes={footnotes} />
    </div>
  );
};

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

const SomeContent = ({footnotes}) => {
  footnotes.push('This is the footnote text.');
  const footnoteIndex = footnotes.length;
  return (<p>Hermansen and Shihipar, et al [{footnoteIndex}]</p>);
};

Когда выполнение достигает компонента Footnotes, тот же самый экземпляр массива сносок будет передан ему через свойство. В этот момент выполнения массив будет заполнен всеми сносками, которые необходимо отобразить. И вы можете просто визуализировать их простым способом:

const Footnotes = ({footnotes}) => {
  const inner = footnotes.map( 
    (footnote, index) => (<li>[{index+1}] {footnote}</li>) );
  return (<ul>{inner}</ul>);
}; 

Эта реализация определенно связана с порядком рендеринга компонентов. Таким образом, порядок компонентов в вашем рендеринге должен соответствовать визуальному порядку, в котором вы хотите, чтобы сноски отображались.

Вот jsfiddle - https://jsfiddle.net/69z2wepo/79222/

person Erik Hermansen    schedule 22.05.2017
comment
Спасибо, это, безусловно, интересный подход, но сложно передать сноски по дереву. Я полагаю, это можно было бы сделать с контекстом, подобным системе, но тогда он не сбрасывался бы при каждом рендеринге. - person Thariq Shihipar; 22.05.2017
comment
Мнения на этот счет разнятся. Я всегда ошибаюсь в сторону явной передачи переменных компонентам, в то время как другим нравится прятать переменные внутри контекста. Ты в стране реакции, детка. Пора передать реквизит, говорю я. - person Erik Hermansen; 22.05.2017
comment
Контекстная система: глобальное хранилище redux... :) - person Juan Mendes; 22.05.2017
comment
Использование магазина, предложенного Хуаном, тоже хорошо, хотя мне нравится думать о случае, подобном вашему (отслеживание сносок), как о данных, которые должны существовать только в рамках одного рендеринга. Поэтому я предпочитаю свое решение. - person Erik Hermansen; 22.05.2017