Как стать автором
Обновить

Комментарии 10

Спасибо за статью, недавно решал подобную задачу для древовидных комментариев, до этого момента не знал, что у компонентов может быть рекурсия, все оказалось очень просто)

Немного стало больно когда увидел тип массива в котором могут быть объекты и массивы, привычнее структура классических массивов с однотипными данными


Например


interface Node {
  id: number,
  name: string, 
  children: Node[]
}

Спасибо за статью

Да, тут как раз и интересный момент :)

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

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

Node с children — это не про отсутствие дженериков. Никто не мешает сделать


interface Node<T> {
  value: T
  children: Node<T>[]
}

И даже, если упороться, передать в компонент функцию-маппер, извлекающую дочерние элементы из ноды


// html
<tree-view [roots]="roots" [getChildren]="getChildren">
// ts
public getChildren = (node: Node) => node.children;

Тут скорее про то, что в полиморфном массиве из статьи нет семантической связи между родительским и дочерними элементами.
Например, директория с тремя файлами представляется внезапно не 1 элементом и не 4, а двумя:


[
  {...dir element...},
  [ {...file 1...}, {...file 2...}, {...file 3...} ]
]   

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

Да, не спорю, такое решение есть и тоже хорошее. Про семантическую связь я размышлял, когда это делал, интерфейс тут определенно выиграет с точки зрения кейса директории с папками. Мое решение скорее от идеи «вложенность вашего массива — вложенность вашего дерева», на мой взгляд, так закладывается меньше контекста

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

Энивей, оба решения хороши и решают эту историю. Думаю, тут мы к серебрянной пуле не придем, но хорошо, что такое мнение появилось и дополнило статью, спасибо!
А что на счет перфоманса? Особенно с этой рекурсией. Вложенность 5 по 5 потянет, например?

Не просядет, но если компонент для каждого item сложный, то нужно тестировать.


Для производительности лучше выбрать вариант из комментариев с children и не забыть trackBy по id, которое сделать обязательным для типа Item

get isArray()

Как вы это объясните? Ведь использование get функций в шаблоне, сказывается на производительности.

Если там onPush стратегия, то разницы нет, поле там или геттер

Зарегистрируйтесь на Хабре, чтобы оставить комментарий