Philip Pegden
Philip Pegden

Reputation: 2134

Why does importing a class make this code fail?

I'm a real beginner in javascript / React...but I'm trying to set-up a tag based on a string value. Why does widget1 fail to get instantiated? (I get an uncaught ReferenceError: FooA is not defined error) What difference does importing the react component make, versus defining it in the same file?

import React, {Component} from "react";
import ReactDOM from "react-dom";

// Assume FooA and FooB have identical definitions
import FooA from './fooa.jsx'

class FooB extends Component {
    render() {
         return(<p>Hello A</p>);
    }
};

class Splash extends Component {
    render() {
        var widget1 = eval('new ' + "FooA")
        var widget2 = eval('new ' + "FooB")
        return (
            <div>
                {(widget1.render())}
                {(widget2.render())}
            </div>
         )
    };
}

ReactDOM.render(<Splash/>, container);

I am passing this through webpack to get a single .js file.

Is there a better way to achieve this?

Upvotes: 2

Views: 76

Answers (2)

Joe Clay
Joe Clay

Reputation: 35787

You're coming at this problem from the wrong angle. If you want to make a component able to render other components in a generic, reusable way, there's three approaches you can take:

Pass the component class as a prop

class Splash extends Component {
    render() {
        let heading = this.props.heading;

        // These have to start with a capital letter, otherwise
        // JSX assumes 'widget1' is a normal HTML element.
        let Widget1 = this.props.widget1;
        let Widget2 = this.props.widget2;

        return (
            <div>
                <h1>{heading}</h1>
                <Widget1 />
                <Widget2 />
            </div>
         )
    };
}

// This can then be used like so:

<Splash heading="My Generic Splash" widget1={FooA} widget2={FooB} />

Pass the component instance as a prop:

class Splash extends Component {
    render() {
        let heading = this.props.heading;

        let widget1 = this.props.widget1;
        let widget2 = this.props.widget2;

        return (
            <div>
                <h1>{heading}</h1>
                {widget1}
                {widget2}
            </div>
         )
    };
}

// This can then be used like so:

let fooA = <FooA />;

<Splash heading="My Generic Splash" widget1={fooA} widget2={<FooB />} />

Pass the components as children:

class Splash extends Component {
    render() {
        let heading = this.props.heading;

        return (
            <div>
                <h1>{heading}</h1>
                {this.props.children}
            </div>
         )
    };
}

// This can then be used like so:

<Splash heading="My Generic Splash">
    <FooA />
    <FooB />
</Splash>

Upvotes: 1

Facundo La Rocca
Facundo La Rocca

Reputation: 3866

You dont have to instantiate Components, React does that for you.

Your Splash component should look like this:

class Splash extends Component {
    render() {
        return (
            <div>
                <FooA />
                <FooB />
            </div>
         )
    };
}

Now lets supouse you want to have some logic to determine which component must be rendered:

class Splash extends Component {
    let comp = (<FooA />);
    if(some condition)
      comp = (<FooB />);

    render() {
        return (
            <div>
                {comp}
            </div>
         )
    };
}

Now let supouse you want just to parametrize the text:

class FooA extends Component {
    render() {
         return(<p>this.props.textToShow</p>);
    }
};

class Splash extends Component {
    let text = 'whatever text you want to show';
    render() {
        return (
            <div>
              <FooA textToShow={text}/>
            </div>
         )
    };
}

You can pass as a prop other components as well:

class FooA extends Component {
    render() {
         return(
           <p>Some text</p>
           {this.props.child}
         );
    }
};

class FooAChild extends Component {
    render() {
         return(
           <p>I am a child</p>
         );
    }
};

class Splash extends Component {
    let child = (<FooAChild />);
    render() {
        return (
            <div>
            <FooA child={child}/>
            </div>
         )
    };
}

Upvotes: 1

Related Questions