diff --git a/README.md b/README.md index 2c55b17..f004e21 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A zero-dependency lightweight clean conditional rendering component for React. -It works similar to if-else and switch case. If first condition gets true in the children tree, then only that one will be executed. An optional props `limit` will allow to limit the number of true conditions to render at a time. By default `limit` is 1. There is another optional props `isTrue` in ReactWhen which allows you to set condition for entire parent conditional component. +It works similar to if-else and switch case. If first condition gets true in the children tree, then only that one will be executed. An optional props `limit` will allow to limit the number of true conditions to render at a time. By default `limit` is 1. There is another optional props `isTrue` in RenderWhen which allows you to set condition for entire parent conditional component. ## RenderWhen Component diff --git a/index.tsx b/index.tsx index 0942457..660a432 100644 --- a/index.tsx +++ b/index.tsx @@ -1,39 +1,51 @@ -/* eslint-disable react/jsx-no-useless-fragment */ import * as React from 'react'; type WhenProps = { - children: React.ReactNode, - isTrue?: boolean, - limit?: number, + children: React.ReactNode; + isTrue?: boolean; + limit?: number; }; -const RenderWhen = ({ limit, isTrue, children }:WhenProps) => { - const list:React.ReactNode[] = []; +type IfProps = { + children: React.ReactNode; + isTrue: boolean; +}; + +type ElseProps = { + children: React.ReactNode; +}; - if (isTrue !== true) { - return null; - } +const RenderWhen = ({ limit = 1, isTrue = true, children }: WhenProps) => { + const result = React.useMemo(() => { + if (!isTrue) return null; - React.Children.map(children, (child:any) => { - const { isTrue: isChildTrue } = child?.props || {}; + const matched: React.ReactNode[] = []; + let fallback: React.ReactNode = null; - if (isChildTrue === true && list.length < limit) { - list.push(child); - } + React.Children.forEach(children, (child) => { + if (!React.isValidElement(child)) return; + + if (child.type === RenderWhen.Else) { + fallback = child; + return; + } + + if ( + child.type === RenderWhen.If && + (child.props as IfProps).isTrue && + matched.length < limit + ) { + matched.push(child); + } }); - return ( - <> - {list} - - ); -}; + return matched.length > 0 ? matched : fallback; + }, [children, isTrue, limit]); -RenderWhen.defaultProps = { - limit: 1, - isTrue: true, + return <>{result}; }; -RenderWhen.If = ({ children, isTrue }) => children; +RenderWhen.If = ({ children }: IfProps): React.ReactElement => <>{children}; +RenderWhen.Else = ({ children }: ElseProps): React.ReactElement => <>{children}; -export default RenderWhen; +export default RenderWhen; \ No newline at end of file