【问题标题】:Why does importing a class make this code fail?为什么导入类会使此代码失败?
【发布时间】:2017-09-18 13:36:47
【问题描述】:

我是 javascript / React 的真正初学者...但我正在尝试基于字符串值设置标签。为什么 widget1 无法实例化? (我得到一个未捕获的 ReferenceError: FooA is not defined 错误)导入 react 组件与在同一个文件中定义它有什么区别?

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);

我通过 webpack 传递它来获取单个 .js 文件。

有没有更好的方法来实现这一点?

【问题讨论】:

  • 你是否在 fooa.jsx 中导出了任何类?也发布它的内容。
  • 您不必手动执行渲染,也不必实例化组件。就这样使用它:
  • 是的。我的其他文件中有“导出默认 FooA”。在第二点上,“FooA”被保存为一个字符串 - 那么代码 可以工作吗?
  • 如何“保持为字符串”?我不明白你的意思...
  • 我将要显示的组件的标签保存在字符串变量中(它已在其他地方生成)。我不想为它映射到的所有可能的 react 组件编写一个大的 switch 语句,只需插入同名的 react 组件。

标签: javascript reactjs


【解决方案1】:

您不必实例化组件,React 会为您完成。

您的 Splash 组件应如下所示:

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

现在让我们假设您想要一些逻辑来确定必须渲染哪个组件:

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

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

现在假设您只想对文本进行参数化:

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>
         )
    };
}

您也可以将其他组件作为道具传递:

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>
         )
    };
}

【讨论】:

  • 这是我考虑过的解决方案,但我想避免编写该逻辑(假设我有 100 个组件)。所以我希望字符串包含我想要的组件的“名称”,并插入该组件。如果我将所有组件定义在与此代码相同的文件中,则它可以正常工作,根据伪代码。
  • 我相信你无法避免这种逻辑。没有办法使用 React 的组件(除非已经发布了一些新的东西并且我还没有意识到)。
  • String 变量没有保存我想要显示的文本,它是我想要插入的反应组件的名称。奇怪的是,如果所有组件类都定义在同一个文件中,它就可以工作。当我将它们移到单独的文件时,代码就会中断。
  • @PhilipPegden:如果你想让你的代码通用,你可以将值(包括其他组件!)作为道具传递给你的组件,或者编写一个返回组件的函数 - 将组件名称存储为字符串这不是一个好计划。
  • 正如@JoeClay 所说,迟早你必须有一个开关或一个条件来确定组件......
【解决方案2】:

你从错误的角度来解决这个问题。如果您想让一个组件能够以通用、可重用的方式呈现其他组件,您可以采用以下三种方法:

将组件类作为道具传递

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} />

将组件实例作为道具传递:

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 />} />

将组件作为子组件传递:

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>

【讨论】:

  • 非常感谢!这看起来像我需要的解决方案 - 但有一个问题,当我尝试它时,它似乎没有用 this.props.widget1 替换 。当我查看输出时,我仍然看到 ,并且 this.props.widget1 持有“FooA”。你认为这可能与我的 webpack 构建设置有关吗?
  • @PhilipPegden:啊,哎呀,这是我的代码中的错误 - 如果您尝试使用小写名称创建 JSX 元素,则假定它是标准 HTML 元素。将更新我的答案。
  • @PhilipPegden:还值得注意的是,您还可以传递组件的实例而不是类(例如&lt;Splash widget1={&lt;Foo1 /&gt;} /&gt;),然后使用普通的{widget1} 语法渲染它们。
  • @PhilipPegden:答案更新得更全面了:)
  • @PhilipPegden:嗯 - 只是预感,但 Webpack 是否配置为运行 jsx 文件的 Babel 加载器?
猜你喜欢
  • 2017-04-20
  • 1970-01-01
  • 1970-01-01
  • 2013-04-27
  • 2019-01-19
  • 1970-01-01
  • 2019-08-31
  • 2023-04-02
  • 2012-12-03
相关资源
最近更新 更多