How to pass props to children according to type in React + Typescript

Viewed 904

Apologies if this has been answered elsewhere, it seems like a basic problem but I wasn't able to find an answer anywhere.

I am trying to find a way to conditionally pass props to children components based on the the type (i.e. component type) of the child.

For instance given a generic functional component

const Parent = ({propA, propB, children, ...props}) => (
    <div {...props}>
        {children}
    </div>
)

in which I expect to receive only A and B components as children. I want propA to be passed only to children of type A and propB to be passed only to children of type B such that

const Parent = ({propA, propB, children, ...props}) => (
  <div {...props}>
      {React.Children.map<React.ReactNode, React.ReactNode>(children, child => {
        if (React.isValidElement(child)) {
          if (/* child if of type A */)
            return React.cloneElement(child, { propA })
          if (/* child if of type B */)
            return React.cloneElement(child, { propB })
        }
      })}
  </div>
3 Answers

if you know the mapping between Component and its respective props, you can create an array of objects and then map over it, while passing it from the parent. Example

//calling of parent
<Parent renderObject = {[
  {prop : propA, comp: compA},
  {prop : propB, comp: compB}
 ]}
 ...restOfTheProps
/>

Now you can actually code something like this using map

const Parent = ({ renderObject, ...props}) => (
  <div {...props}>
      {renderObject.map((renderObj)=>{
          return <renderObj.comp {...renderObj.prop} />
       })}
  </div>
)

instead of using children, you can pass component as props.

You can use child.type

const Parent = ({propA, propB, children, ...props}) => (
  <div {...props}>
      {React.Children.map<React.ReactNode, React.ReactNode>(children, child => {
          if (React.isValidElement(child)) {
              if (child.type===A) {
                  return React.cloneElement(child, { propA })
              } else {
              return React.cloneElement(child, { propB })
              }
          }
      })}
   </div>)

same this you can do it!

<Modal isActive={true} > 
  <h1>Modal here!</h1>
</Modal>

and in Your component do same this:

type Props ={
  children: React.ReactNode;
  isActive: boolean;
}

const Modal:React.FC<Props> = ({children, isActive}) => {
  return isActive && children;
}
export default Modal;
Related