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

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

ただいまの
回答率

90.77%

  • React.js

    719questions

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

React の Class 呼出に失敗します

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 727

sab

score 12

 障害

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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

回答 2

checkベストアンサー

+1

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()の引数に渡す値が不正な値だからです。

React.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 13: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 にする方法ってなにかあるのでしょうか?

    キャンセル

  • 2017/11/15 13:58

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

    キャンセル

  • 2017/11/15 14:00

    > 今回は jsx側 で "document.Hello = <CompClock/>;" と書いて、
    > xhtml 側で、"React.createElement(document.Hello)," とする事で問題を回避しています。

    これは、React.createElement(React.createElement(CompClock))をしているのと同じですよ。
    JSX記法はReact.createElement()のシンタックスシュガーにすぎないので。

    キャンセル

  • 2017/11/15 14:24 編集

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

    お手数お掛けしました。

    キャンセル

0

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

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

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

       <script type="text/babel">
            ReactDOM.render(
              <CompClock/>,
              document.getElementById('root')
            );
        </script>

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

追記

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

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

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

<?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-standalone/6.26.0/babel.js"></script>
        <script src="render.jsx" type="text/jsx"></script>
    </head>
    <body>
        <div id="root"></div>
        <script type="text/jsx">
            ReactDOM.render(
              <CompClock/>,
              document.getElementById('root')
            );
        </script>
    </body>
</html>

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/15 13:34

    ご指摘ありがとうございます。
    ただ、残念ながらこの手は使えません。

    詳細は、前回答の HayatoKamono さんへのコメントを確認して頂きたいのですが、xhtml を利用している関係から、Babel 式を xhtml に直書き出来ない為です。

    xhtml内 でも Babel 式を問題無く記載出来る方法があれば良いのですが..

    キャンセル

  • 2017/11/15 14:30

    xhtmlでjsxが成功したので追記しました。

    > 既存の class を インスタンス化 したものを、object では無く class にする方法ってなにかあるのでしょうか?

    インスタンスをクラスにするという発想自体おかしいと思います。
    結局render関数に渡すのは element (インスタンス) なので、
    1.document.Hello に クラスを入れて、renderのとこでインスタンス化する

    2.document.Hello にインスタンスを入れて、renderのとこでそのまま渡す
    かすればいいと思います。

    キャンセル

  • 2017/11/15 14:35

    追記の記載ありがとうございました。
    babel-standalone の件は知りませんでした。

    ご指摘の内容を反映させた結果、chrome 32, ie11 では動作する事を確認出来ました。

    但し、残念ながら firefox 57 ではやはりダメでした。

    経験則でコメントすると、firefox + xhtml 内では babel の記載はほとんど NG のようです。
    chrome は以外になんとか動くのですが、時々ダメと言う感じでした。

    キャンセル

  • 2017/11/15 14:39

    > インスタンスをクラスにするという発想自体おかしいと思います。
    > 結局render関数に渡すのは element (インスタンス) なので、

    ご指摘ありがとうございます。
    残念ながら、まだ javascript の作法を習得しているとは言えない為、おかしなところも多いかと思います。

    ご指摘参考とさせて頂きます。

    キャンセル

  • 2017/11/15 15:30 編集

    確かに firefox 56 57 で試しましたが、<CompClock/> の部分が削除されるというか、無視されるかんじになりますね。

    どうやら firefox は xhtml に他のブラウザとは異なる扱いをするようです。
    試しに
    &lt;CompClock/&gt;
    としてみたら動きました。しかし今度は chrome で構文エラーとなりました。

    xhtml では inline script tag を使わないほうがいいようです。
    そもそも xhtml を使う理由がないのでは...。

    キャンセル

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

  • ただいまの回答率 90.77%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • React.js

    719questions

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