クラスの名前を含む文字列があります(これはjsonファイルからのものです)。この文字列は、データに使用するレイアウト/テンプレート(jsonでも)をテンプレートクラスに指示します。問題は、レイアウトが表示されないことです。
Home.jsx:
//a template or layout.
var Home = React.createClass({
render () {
return (
<div>Home layout</div>
)
}
});
Template.jsx:
var Template = React.createClass({
render: function() {
var Tag = this.props.template; //this is the name of the class eg. 'Home'
return (
<Tag />
);
}
});
エラーは発生しませんが、レイアウト/ホームクラスも表示されません。 props.templateを確認したところ、正しい情報がログに記録されました。また、DOMでhome要素を確認できます。ただし、次のようになります。
<div id='template-holder>
<home></home>
</div>
次の行を次のように変更した場合:
var Tag = Home;
//this works but it's not dynamic!
任意のアイデア、これをどのように修正できますか?私はそれが単純な修正であるか、私が愚かなことをしていると確信しています。助けていただければ幸いです。これが既に尋ねられた場合は申し訳ありません(私はそれを見つけることができませんでした)。
ありがとう、ユアン
これは機能しません:
var Home = React.createClass({ ... });
var Component = "Home";
React.render(<Component />, ...);
ただし、これは次のようになります。
var Home = React.createClass({ ... });
var Component = Home;
React.render(<Component />, ...);
したがって、string"Home"
とcomponent classHome
をマッピングする方法を見つけるだけです。単純なオブジェクトは基本的なレジストリとして機能し、さらに機能が必要な場合はそこから構築できます。
var components = {
"Home": Home,
"Other": OtherComponent
};
var Component = components[this.props.template];
すべてのコンポーネントを1つのモジュールに収めることができれば、クラスを手動で辞書にマッピングしなくても機能します。
import * as widgets from 'widgets';
var Type = widgets[this.props.template];
...
<Type />
ワイルドカードインポートステートメントは既に辞書であり、コードは前の回答のレジストリのように機能します。
実際、1つの追加マッピングで複数のモジュールを操作できると思います。
import * as widgets from 'widgets';
import * as widgets2 from 'widgets2';
const registry = Object.assign({}, widgets, widgets2);
const widget = registry[this.props.template];
私はこれを完全に行います。実際私はそうだと思います。
同じ問題があり、自分で解決策を見つけました。 「ベストプラクティス」であるかどうかはわかりませんが、問題なく機能し、現在私のソリューションで使用しています。
"evil" eval関数を使用して、動的にコンポーネントのインスタンスを動的に作成できます。何かのようなもの:
function createComponent(componentName, props, children){
var component = React.createElement(eval(componentName), props, children);
return component;
}
次に、必要な場所に呼び出します。
var homeComponent = createComponent('Home', [props], [...children]);
それがあなたのニーズに合っているなら、おそらくあなたはこのようなものを考えることができます。
それが役に立てば幸い。
他の人が示唆したように、静的にリンクされたコードとしてコンポーネントをパッケージに埋め込むことなく、文字列コンテンツから機能する方法は次のとおりです。
import React from 'react';
import { Button } from 'semantic-ui-react';
import createReactClass from 'create-react-class';
export default class Demo extends React.Component {
render() {
const s = "return { render() { return rce('div', null, rce(components['Button'], {content: this.props.propA}), rce(components['Button'], {content: 'hardcoded content'})); } }"
const createComponentSpec = new Function("rce", "components", s);
const componentSpec = createComponentSpec(React.createElement, { "Button": Button });
const component = React.createElement(createReactClass(componentSpec), { propA: "content from property" }, null);
return (
<div>
{component}
</div>
)
}
}
Reactクラスの仕様は文字列s
です。次の点に注意してください。
rce
はReact.createElement
を表し、createComponentSpec
を呼び出すときに最初のパラメーターとして指定されます。
components
は追加のコンポーネントタイプのディクショナリであり、createComponentSpec
を呼び出すときに2番目のパラメーターとして指定されます。これは、競合する名前をコンポーネントに提供できるようにするためです。
たとえば、文字列Button
は、標準のHTMLボタン、またはセマンティックUIのボタンに解決できます。
https://reactjs.org/docs/react-without-jsx.html で説明されているように、 https://babeljs.io を使用してs
のコンテンツを簡単に生成できます。基本的に、文字列はJSXのものを含むことができず、プレーンJavaScriptである必要があります。これが、BabelJSがJSXをJavaScriptに変換することで行っていることです。
React.createElement
をrce
に置き換え、components
辞書を介して外部コンポーネントを解決する必要があります(外部コンポーネントを使用しない場合は、辞書をスキップできます)。 。
上記のコードと同じです。同じ<div>
に2つのセマンティックUI Button
sが含まれています。
JSX render()コード:
function render() {
return (
<div>
<Button content={this.props.propA}/>
<Button content='hardcoded content'/>
</div>
);
}
BabelJSはそれを次のように変換します:
function render() {
return React.createElement("div", null, React.createElement(Button, {
content: this.props.propA
}), React.createElement(Button, {
content: "hardcoded content"
}));
}
そして、上で概説したように置換を行います:
render() { return rce('div', null, rce(components['Button'], {content: this.props.propA}), rce(components['Button'], {content: 'hardcoded content'})); }
createComponentSpec
関数を呼び出すと、Reactクラスの仕様が作成されます。
次に、実際のReact createReactClass
のクラスに変換されます。
そして、React.createElement
で実現しました。
あなたがする必要があるのはメインコンポーネントrender
funcからそれを返すことだけです。
JSXを使用すると、HTMLタグ(文字列)またはReactコンポーネント(クラス))をレンダリングできます。
Var Tag = Homeを実行すると、JSXコンパイラがそれを次のように変換するため、機能します。
var Template = React.createElement(Tag, {});
変数Tagが同じスコープにあり、Reactクラスです。
var Tag = Home = React.createClass({
render () {
return (
<div>Home layout</div>
)
}
});
あなたがするとき
var Tag = this.props.template; // example: Tag = "aClassName"
あなたがやっている
var Template = React.createElement("aClassName", null);
ただし、「aClassName」は有効なHTMLタグではありません。
見て ここ
データベースからロードされたJSON仕様から動的にReactクラスを作成する方法を知りたいと思ったので、いくつか実験してそれを理解しました。私の基本的な考えは、テキストエディターでコードを入力する代わりに、GUIを介してReactアプリを定義することでした。
これはReact 16.3.2と互換性があります。注React.createClass
は独自のモジュールに移動されました。
ここに重要な部分の要約版があります:
import React from 'react'
import ReactDOMServer from 'react-dom/server'
import createReactClass from 'create-react-class'
const spec = {
// getDefaultProps
// getInitialState
// propTypes: { ... }
render () {
return React.createElement('div', null, 'Some text to render')
}
}
const component = createReactClass(spec)
const factory = React.createFactory(component)
const instance = factory({ /* props */ })
const str = ReactDOMServer.renderToStaticMarkup(instance)
console.log(str)
ここでより完全な例を見ることができます: