#reactjs
Вопрос:
Я пытаюсь вернуть массив дочерних компонентов, которые соответствуют определенному имени внутри родительского компонента.
Например:
React.Children.toArray(this.props.children).filter(child => ['TextInput'].includes(child.type.name));
Так что, даже если у меня есть:
<Form>
<div>
<TextInput />
</div>
<div>
<div>
<TextInput />
</div>
</div>
</Form>
Я мог бы вернуть массив из этих двух TextInput
компонентов.
Однако из-за вложенности этих элементов/компонентов фильтр зацикливает только один раз на первой глубине…
Я пытался сделать это рекурсивно, используя flatMap
то, что, как я понял, сделает это:
React.Children.toArray(this.props.children).flatMap(child => ['TextInput'].includes(child.type.name));
Однако, похоже, это сработало не так, как я ожидал… есть ли альтернативный способ найти соответствующие компоненты независимо от глубины элемента?
Ответ №1:
Вам понадобится рекурсивная функция:
function walkAllChildren(root, callback) {
function walk(e, parents) {
callback(e, parents);
const newParents = [...parents, e];
React.Children.toArray(e.props?.children).forEach((c) => {
walk(c, newParents);
});
}
walk(root, []);
}
walkAllChildren(
<main>
<div>
<TextInput />
</div>
<div>
<div>
Hello!
<TextInput />
</div>
</div>
</main>,
(e, parents) => {
if (e.type?.name === "TextInput") {
console.log(e, parents);
}
},
);
распечатки
{type: ƒ TextInput(), key: ".0", ref: null, props: Object, _owner: FiberNode…}
(2) [Object, Object]
{type: ƒ TextInput(), key: ".1", ref: null, props: Object, _owner: FiberNode…}
(3) [Object, Object, Object]
(и расширение Object
массивов покажет происхождение каждого текстового ввода).
РЕДАКТИРОВАТЬ: то же самое, что и в TypeScript, если вам нужны типы:
function walkAllChildren(
root: React.ReactNode,
callback: (
element: React.ReactNode,
parents: readonly React.ReactNode[]
) => void
) {
function walk(element: React.ReactNode, parents: readonly React.ReactNode[]) {
if (element === null || element === undefined) return;
callback(element, parents);
const newParents = [...parents, element];
const children = (element as any).props?.children;
React.Children.toArray(children).forEach((child) => {
walk(child, newParents);
});
}
walk(root, []);
}
Комментарии:
1. Спасибо, что нашли элементы. Должен ли я иметь возможность вызывать методы для этих возвращаемых элементов? Я пытался получить к ним доступ, но могу получить доступ только к свойствам, но возвращает функцию, не найденную при попытке вызвать для нее метод.
2. Например, я надеялся, что смогу сделать:
this.formFields[0].exampleMethod()
что вызовет этот метод для первого дочернего элемента в возвращаемом массиве.3. Ах, я все понял… пришлось добавить ссылку на
TextInput
, а затем я могу получить доступ к методу следующим образом:this.formFields[0].ref.current.exampleMethod()
. В конечном итоге для доступа к дочерним компонентам React от других требуется довольно много работы 😀