GarouDan
GarouDan

Reputation: 3833

React. How to pass props inside a component defined on a prop?

If we have the following structure on a React application:

class BasePage extends React.Component {

    render() {
        return <div>
            {this.props.header}
            {/*<Header title={this.props.title} />*/}
        </div>
    }
}

BasePage.defaultProps = {
    header: <header>Base Page</header>
}

class Header extends React.Component {

    render() {
        return <header>
            <h1>{this.props.title}</h1>
        </header>
    }
}

class TestPage extends BasePage {
}

TestPage.defaultProps = {
    header: <Header />
}

class Root extends React.Component {

  render() {
    return <div>
            <TestPage
                title="Test Page Title"
            />
    </div>
  }
}

ReactDOM.render(
    <Root />,
    document.getElementById('root')
)

If we have a common component like <Header /> we can pass a title property easily like <Header title={this.props.title} />.

But how can we pass props inside a component if this component is defined as a prop itself?

For example, how can we do something like:

{this.props.header title={this.props.title}}

So it will render the Test Page Title correctly?

Important note: we could overwrite the render method inside the Test component. But the purpose of this question is to solve this problem without doing this.

Upvotes: 4

Views: 4827

Answers (2)

Sauce
Sauce

Reputation: 662

This seems like a great use case for React.cloneElement.

React.cloneElement(this.props.header, { title: this.props.title });

It returns a clone of the component with the new props included.

Upvotes: 1

Michael Peyper
Michael Peyper

Reputation: 6944

Firstly, props are read-only and a component should never be update it's own props, so lines like

componentWillMount() {
    this.props.header = <header>Base Page</header>
}

should not be used. defaultProps can do what I think you are trying to do:

class BasePage extends React.Component {
    render() {
        return <div>
            {this.props.header}
            {/*<Header title={this.props.title} />*/}
        </div>
    }
}

BasePage.defaultProps = {
    header: <header>Base Page</header>
}

Secondly, inheritance is not often done in React. I'm not saying don't do what your'e doing, but take a read of the docs and see if there is perhaps a simpler way to achieve the same goals.

Finally, setting props on components passed as props. There are a couple different ways to do this.

If you pass the Component rather than the <Component /> you can add props like normal:

ChildComponent = (props) => {
  const HeaderComponent = props.header
  return <HeaderComponent title="..." />
}

ParentComponent = () => <ChildComponent header={Header} />

You can clone the element to override props:

ChildComponent = (props) => {
  const HeaderComponent = React.cloneElement(props.header. { title: "..." })
  return <HeaderComponent />
}

ParentComponent = () => <ChildComponent header={<Header />} />

NOTE: I have used functional components instead of class components for brevity, but the concepts are the same.

Upvotes: 3

Related Questions