попытался решить все через рекурсию
Рекурсией конечно можно:
const createTree = (data, parentId = null) =>
data.reduce((acc, n) => (
parentId === n.parentId && (
acc[acc.length] = Object.assign(
{ children: createTree(data, n.id) },
n
)
),
acc
), []);
Но вовсе не обязательно:
function createTree({
data,
key = 'id',
parentKey = 'parentId',
childrenKey = 'children',
}) {
const tree = Object.fromEntries(data.map(n => [
n[key],
{ ...n, [childrenKey]: [] },
]));
return Object.values(tree).filter(n => !(
tree[n[parentKey]] && tree[n[parentKey]][childrenKey].push(n)
));
}