Home > Software design >  How to access the child of a prop in react typescript?
How to access the child of a prop in react typescript?

Time:11-15

<MyComponent>
  <button>Click me</button>
</MyComponent>

interface MyComponentProps {
   children: ???;
}

const MyComponent: FC<MyComponentProps> = ({children}) => {
    const string = children.???  //I want the string to be "Click me"
}

I tried so many combinations but I always get undefined, thank you so much for your help.

CodePudding user response:

As others have pointed out, you probably shouldn't be accessing the props of a child, as it is an anti-pattern in React. However, it is possible.

Let's do it right, and write a function to do so safely.

First a few type predicate helpers.

const isElement = (child: React.ReactNode): child is React.ReactElement =>
  (child as React.ReactElement)?.props !== undefined;
const isLeaf = (child: React.ReactNode): child is React.ReactText =>
  typeof child === 'string' || typeof child === 'number';

Then a recursive function, that recursively maps over children, picking out string and numbers. Because children can be an array, we return an array of strings or numbers.

function extractText(children: React.ReactNode): React.ReactText[] {
  return React.Children.toArray(children).reduce<React.ReactText[]>((previous, child) => {
    if (isElement(child)) {
      return [...previous, ...extractText(child.props.children)];
    }

    if (isLeaf(child)) {
      return [...previous, child];
    }

    return previous;
  }, []);
}

Finally, put it all together.

const MyComponent = ({ children }: { children: React.ReactNode }): JSX.Element => {
  const string = extractText(children)[0];
  console.log(string); // Click me
  return <>{children}</>;
};

export default function App() {
  return (
    <MyComponent>
      <button>Click me</button>
    </MyComponent>
  );
}

Link to Sandbox

CodePudding user response:

You want to type your children as ReactElement

You will then access props by children.props

<MyComponent>
  <button>Click me</button>
</MyComponent>

interface MyComponentProps {
   children: ReactElement;
}

const MyComponent: FC<MyComponentProps> = ({children}) => {
    const string = children.props.children
}

sandbox with the code:

import { ReactElement } from "react";
import "./styles.css";

interface MyComponentProps {
  children: ReactElement;
}

const MyComponent = ({ children }: MyComponentProps) => {
  const string = children.props.children;
  return <>{string}</>;
};

export default function App() {
  return (
    <MyComponent>
      <button>Click me</button>
    </MyComponent>
  );
}

I created a little different sandbox

import { ReactElement, ReactNode } from "react";
import "./styles.css";

type ChildProps = {
  value: string;
  children: ReactNode;
};

const Child = (props: ChildProps) => {
  return (
    <>
      the child component ={props.value} {props.children}
    </>
  );
};

type ComponentProps = {
  children: ReactElement;
};

const Component = ({ children }: ComponentProps) => {
  const { value, children: nestedChildren } = children.props;
  return (
    <>
      <p>value = {value}</p>
      <p>nested children = {nestedChildren}</p>
      <p>children = {children}</p>
    </>
  );
};

export default function App() {
  return (
    <div className="App">
      <Component>
        <Child value="test">some inner text</Child>
      </Component>
    </div>
  );
}

Output:

value = test

nested children = some inner text

children = the child component =test some inner text
  • Related