import type { ReactElement } from "react"; import React from "react"; import { Case } from "./Case"; import { Default } from "./Default"; import { getConditionResult } from "./getConditionResults"; import { isFunction } from "./isThenable"; import type { FCWithImplicitChildren } from "./types"; import { _memo, _shallowFn } from "./utils"; /** * It will render the first matching ``, or the first encountered `` (or `null`). * * This component can contain any number of `` and one `` blocks * @param __namedParameters Children to pass into the `` component */ const SwitchFn: FCWithImplicitChildren = ({ children }) => { // -- Inspired by react-router -- // We use React.Children.forEach instead of React.Children.toArray().find() // here because toArray adds keys to all child elements and we do not want // to trigger an unmount/remount for two children s or s let matchingCase: ReactElement | undefined; let defaultCase: ReactElement | undefined; // If the children are a function then resolve it first if (isFunction(children)) { children = children(); } React.Children.forEach(children, (child) => { // not a valid react child, don't add it /* istanbul ignore next - This is only a safe fail for people writing bad code */ if (!React.isValidElement(child)) { return; } if (!matchingCase && child.type === Case) { const { condition } = child.props; const conditionResult = getConditionResult(condition); if (conditionResult) { matchingCase = child; } // else not matching condition, don't add it } else if (!defaultCase && child.type === Default) { defaultCase = child; } // else unknown type, don't add it }); return matchingCase ?? defaultCase ?? null; }; export const Switch = _memo(SwitchFn, _shallowFn);