Wizard-of-Koz
Wizard-of-Koz

Reputation: 1787

How to pass props props from Parent to this.props.children in React

I have difficulties trying to pass props to this.props.children. I know there's a few similar posts, however, I believe I have tried most of the accepted solutions, and it's still not behaving and expected. So, I guess I'm missing something vital.

The general idea is this: I have a <NavBar> component that I would like to wrap around my pages as shown below. I'd like for the wrapped page to accept props passed down from the <NavBar> component.

<NavBar>
    <Container>
        <Grid container>
            <Grid item>
               ...
            </Grid>
        </Grid>
    </Container>
</NavBar>

Currently my <NavBar> is defined as such:

class NavBar extends React.Component<React.PropsWithChildren<NavBarProps>, NavBarState>

So, my component has a prop children?: React.ReactNode. In my render() method I am rendering an <AppBar> (from Material UI library) underneath which I display the children similar as such:

render() {
    const {children} = this.props;
    return(
        <>
            <AppBar>...</AppBar>
            {children}
        </>
    )
}

Some attempts I've had:

render() {
    const children = React.cloneElement(this.props.children as React.ReactElement, {
        test: "test"
    });

    return(
        <>
            <AppBar>...</AppBar>
            {children}
        </>
    )
}

What I expect: In this case, I would like to be able to access the test props from any page wrapped within <NavBar> like this.props.test

I also tried:

const children = React.Children.map(this.props.children as React.ReactElement, (child) =>
    React.cloneElement(child, { test: "test" })
);

&

const children = React.Children.map<ReactNode, ReactNode>(this.props.children, (child) => {
  if (React.isValidElement(child)) {
    return React.cloneElement(child, { test: "test" });
  }
});

Result so far: I've been unsuccessful and trying to access this.props.test from my page returns undefined.

Upvotes: 2

Views: 792

Answers (1)

Brian Thompson
Brian Thompson

Reputation: 14395

I don't see anything wrong with your third attempt. Here is a working example using that method. Notice unlike your second attempt, you do need to return from the map.

function Test() {
  return (
    <Parent>
      <Child />
    </Parent>
  );
}

class Parent extends React.Component {
  render() {
    const children = React.Children.map(this.props.children, (child) => {
      return React.cloneElement(child, {test: 'test'});
    });

    return (
      <div>
        <h3>Parent</h3>
        {children}
      </div>
    );
  }
}

class Child extends React.Component {
  render() {
    return (
      <div>
        <h3>Child</h3>
        Test Prop: {this.props.test}
      </div>
    );
  }
}

ReactDOM.render(<Test/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"/>

Upvotes: 1

Related Questions