user3378165
user3378165

Reputation: 6896

Parent component that can get different components

I have a <Panel/> component that has to get different changing components.

For example one time- the <Panel/> needs to contain a <Dropdown/> component, a second time a <TextInput/> and in the third time a <Checkbox/>.

How can I make this <Panel/> component to get different components?

The <Panel/> component:

import React from "react";
import { css } from "emotion";
import colors from '../../styles/colors';
import PanelHeader from "./PanelHeader";

export default function Panel({ active, panelHeader}) {
    const styles = css({
        borderRadius: 4,
        backgroundColor: "white",
        border: `1px solid ${ active ? colors.blue : colors.grayLight }`,
        width: 540,
        padding: 32,

    });
    return (
        <div className={styles}>
            {panelHeader && <PanelHeader headerType={panelHeader} />}
        </div>
    );
}

The Panel story:

import React from "react";
import { storiesOf } from "@storybook/react";

import Panel from "../components/Panel";
import colors from '../styles/colors';

import PanelHeader from "../components/Panel/PanelHeader";

storiesOf("Panel", module)
    .add("Default", () => (
        <Panel></Panel>
    ))
    .add("Active", () => (
        <Panel active></Panel>
    ))

storiesOf("Panel/PanelHeader", module)
    .add("Default", () => (
        <PanelHeader headerType="Identity document" color={colors.gray}>1</PanelHeader>
    ))
    .add("Active", () => (
        <PanelHeader headerType="Identity document" color={colors.blue}>1</PanelHeader>
    ))

Upvotes: 0

Views: 39

Answers (1)

Marko Gresak
Marko Gresak

Reputation: 8217

You can change Panel to accept children prop, pass it where you Render <Panel> and pass in the corresponding component.

For example:

// PropType for children is `PropTypes.node`
export default function Panel({ active, panelHeader, children}) {
    // ...
    return (
        <div className={styles}>
            {children}
        </div>
    );
}

// ...

<Panel><Dropdown /></Panel>

// or

<Panel><TextInput /></Panel>

Or, you could pass in a component class/function and render it inside:

export default function Panel({ active, panelHeader, ChildComponent}) {
    // ...
    return (
        <div className={styles}>
            {/* This is like any other component, 
                you can pass in props as usual. */}
            {/* It's important for the name to start with an uppercase letter, 
                otherwise the JSX compiler will turn this in a string! */}
            <ChildComponent />
        </div>
    );
}

// ...

<Panel ChildComponent={Dropdown}></Panel>

// or

<Panel ChildComponent={TextInput}></Panel>

This pattern is called component composition. You can read more in React docs: https://reactjs.org/docs/composition-vs-inheritance.html

Upvotes: 1

Related Questions