From ba345f641aed73204dc04426446ae8b5030a22f3 Mon Sep 17 00:00:00 2001 From: inokawa <48897392+inokawa@users.noreply.github.com> Date: Sat, 12 Aug 2023 13:02:58 +0900 Subject: [PATCH] Optimize children flattening --- src/react/utils.ts | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/src/react/utils.ts b/src/react/utils.ts index 91544e431..19b7d2c5d 100644 --- a/src/react/utils.ts +++ b/src/react/utils.ts @@ -1,19 +1,37 @@ -import { Children, ReactElement, ReactFragment, ReactNode } from "react"; +import { ReactElement, ReactFragment, ReactNode } from "react"; import { exists } from "../core/utils"; export const refKey = "current"; export const emptyComponents = {}; -export const flattenChildren = (children: ReactNode) => { - const arr: (ReactElement | ReactFragment | string | number)[] = []; - Children.forEach(children, (e) => { - if (!exists(e) || typeof e === "boolean") { - return; +type ItemElement = ReactElement | ReactFragment | string | number; + +const forEach = (children: ReactNode, elements: ItemElement[]) => { + if (Array.isArray(children)) { + for (const c of children) { + forEach(c, elements); } - arr.push(e); - }); - return arr; + } else if (!exists(children) || typeof children === "boolean") { + // filter out, that is the same as React.Children.toArray + } else { + elements.push(children); + } +}; + +// Relace React.Children.forEach with our tiny implementation. +// In our usage, just flatten children array keeping element instances and their keys, React.Children is redundant and slow. +// +// - React.Children.toArray is slow because it clones element instance. +// - React.Children.map is slow because it clones element instance. +// - React.Children.forEach is slow because it escapes and modifies keys even if they are unused. +// +// And React.Children seems to be in maintenance mode so it's unlikely it would be improved and ported to older versions. +// https://github.com/reactjs/rfcs/pull/61#issuecomment-584402735 +export const flattenChildren = (children: ReactNode): ItemElement[] => { + const elements: ItemElement[] = []; + forEach(children, elements); + return elements; }; export type MayHaveKey = { key?: React.Key };