質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

解決済

2回答

1893閲覧

React の Class 呼出に失敗します

sab

総合スコア20

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

1グッド

0クリップ

投稿2017/11/15 02:38

編集2017/11/15 03:07

障害

React の Class を呼ぼうとすると、ブラウザ環境でエラーが発生し、呼出に失敗します。

環境

firefox 56 & chrome 62
babel-core 5.8.38
react 15.6.2
react-dom 15.6.2

症状

React の React.Component 拡張 Class の 呼出に失敗します。
エラーが発生する要因がどうにも解りません。

  • (ファイル) render.jsx:

class CompClock extends React.Component {
.....
}

a) document.Hello = CompClock; // -> 意図した動作をする
b) document.Hello = <CompClock/>; // -> ブラウザで下記のエラーが出る


  • firefox console からのキャプチャ

Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: object.

Uncaught Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
at invariant (react-dom.js:17859)
at ReactCompositeComponentWrapper.instantiateReactComponent [as _instantiateReactComponent] (react-dom.js:15950)
at ReactCompositeComponentWrapper.performInitialMount (react-dom.js:4770)
at ReactCompositeComponentWrapper.mountComponent (react-dom.js:4661)
at Object.mountComponent (react-dom.js:11409)
at mountComponentIntoNode (react-dom.js:9646)
at ReactReconcileTransaction.perform (react-dom.js:14573)
at batchedMountComponentIntoNode (react-dom.js:9668)
at ReactDefaultBatchingStrategyTransaction.perform (react-dom.js:14573)
at Object.batchedUpdates (react-dom.js:8729)


詳細

React の学習を兼ねたコードを作成して挙動の調査を進めています。

今後を踏まえ、React.Component の拡張 Class を作成 (render.jsx) し、現在時刻をリアルタイム(秒単位)にブラウザへ表示するコードを作成しました。

document.Hello = "React Class" としてインスタンスを投入し、index.xhtml から、document.Hello を呼び出してレンダリングさせています。

render.jsx "a)" の記載方法の場合は問題無く秒単位で表示が変わるのですが、同 "b)"の場合 "症状"に記載のエラーが表示されて表示がされません。
何となく "new CompClock" のようなケースの時に NG のように思えますが、確証はありません。

尚、フェーズとしては各種技術の実験段階ですので、代替え案云々と言う事は考えていません。

ソースコード

  • (ファイル) index.xhtml

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>05</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> <script src="https://unpkg.com/react@15/dist/react.js"></script> <script src="https://unpkg.com/react-dom@15/dist/react-dom.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.38/browser.js"></script> <script src="render.jsx" type="text/babel"></script> </head> <body> <div id="root"></div> <script type="text/babel"> ReactDOM.render( React.createElement(document.Hello), document.getElementById('root') ); </script> </body> </html>

  • (ファイル) render.jsx:

class CompClock extends React.Component { constructor(props) { super(props); this.state = { now: (new Date()) }; setInterval(e => { this.setState({now: (new Date())}); }, 1000); } fmt(v) { const s = "00" + v; return(s.substr(s.length - 2, 2)); } render() { // const now = this.state.now; const now = new Date(); const hh = this.fmt(now.getHours()); const mm = this.fmt(now.getMinutes()); const ss = this.fmt(now.getSeconds()); return( <div>{hh}:{mm}:{ss}</div> ); } }; console.log("start.."); // document.Hello = CompClock; document.Hello = <CompClock/>;

HayatoKamono👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

Uncaught Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.

エラーメッセージに書いてある通り、原因はReact.createElement()の引数に渡す値が不正な値だからです。

JavaScript

1React.createElement(document.Hello),

https://reactjs.org/docs/react-api.html#createelement

上記の公式ページに記載がある通り、React.createElement()の第一引数に渡す値の型は、'div'などのタグを示す文字列か、以下のようなコンポーネントを生成するクラスか関数である必要があります。

class CompClock extends React.Component { render() { return null; } } const CompClock = props => { return null; }

console.log(<CompClock />);でログを確認してみるとわかると思いますが、{$$typeof: Symbol(react.element), key: null, ref: null, props: {…}, type: ƒ, …}のようなオブジェクトがログに出力されるはずです。

エラーメッセージに書いてある通り、Objectが引数に渡っていることがエラーの原因かと思われます。

投稿2017/11/15 03:28

HayatoKamono

総合スコア2415

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sab

2017/11/15 04:30

ご指摘ありがとうございます。確かに、 console.log(document.Hello); としたところ、ご指摘のような結果が得られました。 C や Java のように、class/ function の参照渡しを 勝手にイメージしていました。 javascript に対する私の知識不足でした。 ただ、正直対応策が不明です。 次回答の karamarimo さんからご指摘頂いた手法は残念ながら使えません。 xhtml で作成している(これは必須) のですが、この場合、xhtml 内に Babel 式に ... <CompClock/> と script 中に直書きしてしまうと、高い確率でエラーになってレンダリングされません。 (html なら良かったのですが...) で、 今回は jsx側 で "document.Hello = <CompClock/>;" と書いて、xhtml 側で、"React.createElement(document.Hello)," とする事で問題を回避しています。 結果、 "document.Hello = CompClock" と書く分には class 型で渡されましたが、"document.Hello = <CompClock/>" と書くと object 型で渡される、と言う落ちになったと言う事かと思います。 追記すれば、"document.Hello = new CompClock()" とした場合も同じエラーですので理由は同じかと思います。 javascript の知識が不足していますので恥を忍んで聞いてしまいますが、既存の class を インスタンス化 したものを、object では無く class にする方法ってなにかあるのでしょうか?
HayatoKamono

2017/11/15 04:58

`document.Hello = <CompClock/>;`のバージョンで、 ``` ReactDOM.render( document.Hello, document.getElementById('root') ); ``` では、うまく行きませんか?
HayatoKamono

2017/11/15 05:00

> 今回は jsx側 で "document.Hello = <CompClock/>;" と書いて、 > xhtml 側で、"React.createElement(document.Hello)," とする事で問題を回避しています。 これは、React.createElement(React.createElement(CompClock))をしているのと同じですよ。 JSX記法はReact.createElement()のシンタックスシュガーにすぎないので。
sab

2017/11/15 05:46 編集

おぉ感動です、うまく動きました。ありがとうございます。 "ReactDOM.render()" と "React.createElement() のリファレンスを確認しろ" って話でしたね。 お手数お掛けしました。
guest

0

エラーにある通り、React.createElementの引数にはstringかclassしか渡せません。

CompClockはclassですが、<CompClock/>はobjectです。

そもそもCompClockをグローバルで定義しているので、document.Helloに入れる必要がないと思います。また、createElementを使う理由もありません。

lang

1 <script type="text/babel"> 2 ReactDOM.render( 3 <CompClock/>, 4 document.getElementById('root') 5 ); 6 </script>

このようにしてみてはどうでしょうか。

##追記

Babel 式を xhtml に直書き出来ない

ReactDOM.renderのところに<CompClock/>を書いて試してみたところ、Uncaught ReferenceError: CompClock is not definedとエラーがでました。

以下のように、ブラウザ用のbabelであるbabel-standaloneを使えばうまくいきました(chrome 61)。

lang

1<?xml version="1.0" encoding="UTF-8"?> 2<!DOCTYPE html> 3<html xmlns="http://www.w3.org/1999/xhtml"> 4 <head> 5 <title>05</title> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"/> 7 <script src="https://unpkg.com/react@15/dist/react.js"></script> 8 <script src="https://unpkg.com/react-dom@15/dist/react-dom.js"></script> 9 <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.js"></script> 10 <script src="render.jsx" type="text/jsx"></script> 11 </head> 12 <body> 13 <div id="root"></div> 14 <script type="text/jsx"> 15 ReactDOM.render( 16 <CompClock/>, 17 document.getElementById('root') 18 ); 19 </script> 20 </body> 21</html>

投稿2017/11/15 03:23

編集2017/11/15 05:20
karamarimo

総合スコア2551

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sab

2017/11/15 04:34

ご指摘ありがとうございます。 ただ、残念ながらこの手は使えません。 詳細は、前回答の HayatoKamono さんへのコメントを確認して頂きたいのですが、xhtml を利用している関係から、Babel 式を xhtml に直書き出来ない為です。 xhtml内 でも Babel 式を問題無く記載出来る方法があれば良いのですが..
karamarimo

2017/11/15 05:30

xhtmlでjsxが成功したので追記しました。 > 既存の class を インスタンス化 したものを、object では無く class にする方法ってなにかあるのでしょうか? インスタンスをクラスにするという発想自体おかしいと思います。 結局render関数に渡すのは element (インスタンス) なので、 1.document.Hello に クラスを入れて、renderのとこでインスタンス化する か 2.document.Hello にインスタンスを入れて、renderのとこでそのまま渡す かすればいいと思います。
sab

2017/11/15 05:35

追記の記載ありがとうございました。 babel-standalone の件は知りませんでした。 ご指摘の内容を反映させた結果、chrome 32, ie11 では動作する事を確認出来ました。 但し、残念ながら firefox 57 ではやはりダメでした。 経験則でコメントすると、firefox + xhtml 内では babel の記載はほとんど NG のようです。 chrome は以外になんとか動くのですが、時々ダメと言う感じでした。
sab

2017/11/15 05:39

> インスタンスをクラスにするという発想自体おかしいと思います。 > 結局render関数に渡すのは element (インスタンス) なので、 ご指摘ありがとうございます。 残念ながら、まだ javascript の作法を習得しているとは言えない為、おかしなところも多いかと思います。 ご指摘参考とさせて頂きます。
karamarimo

2017/11/15 06:37 編集

確かに firefox 56 57 で試しましたが、<CompClock/> の部分が削除されるというか、無視されるかんじになりますね。 どうやら firefox は xhtml に他のブラウザとは異なる扱いをするようです。 試しに &lt;CompClock/&gt; としてみたら動きました。しかし今度は chrome で構文エラーとなりました。 xhtml では inline script tag を使わないほうがいいようです。 そもそも xhtml を使う理由がないのでは...。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問