One of the most important characteristics of React is that it lets you compose different components to build your UI.

    Let's think about a use case. Imagine we want to build a reusable Dialog component. Assume it's a simple dialog component - nothing fancy. When this component is rendered we want to display some content within a modal window.

    1. class Dialog extends React.Component {
    2. render(){
    3. return (
    4. <div className={'dialog'}>
    5. //display content of dialog
    6. //????? but we don't know what to display
    7. </div>
    8. )
    9. }
    10. }

    That sounds simple except we don't know what the content of the dialog is going to be. Imagine at one place we might want to display an employee contact within a dialog and at some other place we might want to display a grid. This component itself has no knowledge of it beforehand. And if we wanted to make this component truly reusable it should not have any knowledge of it beforehand.

    The job of the Dialog component is to render a modal window but it shouldn't care about the content - we should be able to use this component at different places to render different things.

    How do we tell this dialog to display different things?

    There are couple common patterns used in React to do this.

    • props.childrenOne way to achieve this goal of reusing Dialog anywhere we like without Dialog having to know what it's displaying is by using the children props. Let's look at one potential usage of Dialog component below to understand this:
    1. //Displays EmployeeProfile inside a Dialog
    2. class EmployeeProfileDialog extends React.Component {
    3. render(){
    4. //We have passed a child component inside the Dialog
    5. return (
    6. <Dialog>
    7. <EmployeeProfile />
    8. </Dialog>
    9. )
    10. }
    11. }

    Here we have a component called EmployeeProfile (any other valid React component would also work here) as a "child" of Dialog. When we pass a "child" to a component it will be available inside that component as a props called children. So in this case, EmployeeProfile will be available inside the Dialog component as props.children. We can rewrite render function of Dialog so that it renders props.children.

    1. class Dialog extends React.Component {
    2. render(){
    3. //Render the children provided to this component
    4. //Here we don't really care what the children is
    5. return (
    6. <div className={'dialog'}>
    7. {this.props.children}
    8. </div>
    9. )
    10. }
    11. }

    Think about what we did here. The Dialog component really doesn't know what it's children would be beforehand. Whoever is using this Dialog component can pass in any children that they like. Within the render function Dialog says - hey I'll display anything my user passes me as children, I don't need to know what that is.

    This my friend is composition and this is mighty powerful if you want to write reusable components.

    • render propsAnother pattern to achieve a similar thing in React is by using what's known as "render props" pattern.

    So now let's take the same dialog example but let's make it more sophisticated. Imagine the dialog has a header, body and footer section. We want the user of this component to be able to display anything they like within either of those three sections.

    1. class Dialog extends React.Component {
    2. render(){
    3. return (
    4. <div className={'dialog'}>
    5. <div className={'dialogHeader'}>
    6. {
    7. /** user of this component should be able to display any header inside here */
    8. }
    9. </div>
    10. <div className={'dialogBody'}>
    11. {
    12. /** user of this component should be able to display any body inside here */
    13. }
    14. </div>
    15. <div className={'dialogFooter'}>
    16. {
    17. /** user of this component should be able to display any footer inside here */
    18. }
    19. </div>
    20. </div>
    21. )
    22. }
    23. }

    The props.children approach we used above might not work well here. All the children we pass as "children" would be available as props.children and it might be little cumbersome to split the children into our three segments - "header", "body" and "footer". Wouldn't it be nice if we could tell the Dialog component explicitly what it should render within each "header", "body" and "footer" section?

    We can use the "render props" pattern to do exactly that. All this means is that we can pass three render functions as props that tells the dialog what it should render inside each segment. For example, lets look at a usage:

    1. class EmployeeProfileDialog extends React.Component {
    2. render(){
    3. return (
    4. <Dialog
    5. renderHeader={() => <EmployeeProfileHeader />}
    6. renderBody={() => <EmployeeProfileBody />}
    7. renderFooter={() => <EmployeeProfileFooter />}
    8. />
    9. )
    10. }
    11. }

    Here, all we are really doing is passing three different props called renderHeader, renderBody and renderFooter. They are all just functions, and when called will return the appropriate React component to display. Now we can edit the Dialog component to get it working as expected:

    1. class Dialog extends React.Component {
    2. render(){
    3. return (
    4. <div className={'dialog'}>
    5. <div className={'dialogHeader'}>
    6. {this.props.renderHeader()}
    7. </div>
    8. <div className={'dialogBody'}>
    9. {this.props.renderBody()}
    10. </div>
    11. <div className={'dialogFooter'}>
    12. {this.props.renderFooter()}
    13. </div>
    14. </div>
    15. )
    16. }
    17. }

    Here, instead of displaying this.props.children like we did previously, we executed the different props functions as appropriate on the different sections. Whatever is returned from that function during runtime will be displayed within that section. The Dialog component remains completely agnostic to what it's displaying.

    Let's do some exercises shall we? Please open the exercise file and follow the instructions to make the appropriate changes.

    There are three things I would like you to note here:

    • We named those props above with render prefix (renderHeader, renderFooter etc) but it's just a naming convention, we could have named it anything. It's just nice to prefix it with render because someone looking at our code would easily be able tell that we are using this props function to render something.

    • The "render" props we passed is just any regular javascript function, its just that it's returning some component. We can do really anything here that we can do in a javascript function. When we called these function inside the Dialog we could pass some arguments if we like. The only limit here really is your imagination.

    • We can pass around components in React as props, just like we can pass an object or string or function. At the end of the day, React components are just functions. So take the liberty of passing it around.