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

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

ただいまの
回答率

91.35%

  • JavaScript

    11222questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • React.js

    376questions

    A JavaScript library for building user interfaces

  • Firebase

    202questions

    Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

Reactで'setState' of nullのエラーが解決できない

解決済

回答 1

投稿 2017/11/26 14:32 ・編集 2017/11/26 15:26

  • 評価
  • クリップ 1
  • VIEW 54

psp7

score 3

初めて質問させていただきます。

最近,React.jsを勉強し始めたのですが、setStateメソッドの部分で'setState' of nullというエラーが出てしまい、全く先に進めなくなってしまいました。
Reactについて詳しい方にご教授いただければと思います。

開発環境: React.js + Firebase

databaseには、firebaseを使っており、ここからデータを読み込んで、Stateのtweetsに値を格納したいと思っております。格納できれば解決するのですが、どうしてもわかりません。
コードは以下です。

このコードで、componentDidMount()のthis.setStateの部分でエラーが起きてしまいます。

エラー文は以下です。

Uncaught TypeError: Cannot read property 'setState' of null
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta lang="ja">
    <link rel="stylesheet" type="text/css" href="css/style.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
    <script src="https://www.gstatic.com/firebasejs/4.6.2/firebase.js"></script>
</head>

<body>
    <div id="tweet"></div>

    <script type="text/babel">
        // Initialize Firebase
        var config = {
            ********非表示にしています******
        };
        firebase.initializeApp(config);

        var firebaseRef = firebase.database().ref();
        var tweetsRef = firebaseRef.child("tweets");

        // メインツイート画面
        class TweetContainer extends React.Component{

            constructor(props) {
            super(props);
                this.state = {tweets: [
                    { id: 1, user: 'Tom',   text: 'Good morning' },
                    { id: 2, user: 'John',  text: 'Good afternoon' },
                    { id: 3, user: 'Emily', text: 'Good evening' }
                ]};
                console.log("initialized");

                this.componentDidMount = this.componentDidMount.bind(this);
          }

            componentDidMount(){
                tweetsRef.on("value", function(snapshot){
                    this.setState({ //エラー部分
                        tweets: snapshot.val()
                    });
                });
            }

            render(){
                var tweetItems = this.state.tweets.map(function(tweet){
                    return (
                        <TweetItem tweet={tweet} />
                    );
                });

                return(
                    <div className="tweetContainer">
                        {tweetItems}
                        <TweetForm />
                    </div>
                );
            }
        }

        //ツイートアイテム
        class TweetItem extends React.Component{
            constructor(props) {
            super(props);
          }

            render(){
                return(
                    <div className="tweetItem">
                        <div className="tweet">{this.props.tweet.text}</div>
                    </div>
                );
            }
        }

        //送信フォーム
        class TweetForm extends React.Component{
            constructor(props) {
            super(props);
                this._onClick = this._onClick.bind(this);
          }

            _onClick(e){
                    tweetsRef.push({
                        text: ReactDOM.findDOMNode(this.refs.inputValue).value
                    });
            }

            render(){
                return(
                    <div className="tweetForm">
                        <input ref="inputValue" type="text" placeholder="message..." />
                        <input type="button" value="送信" onClick={this._onClick.bind(this)}/>
                    </div>
                );
            }
        }

        //レンダリング
        ReactDOM.render(
            <TweetContainer />,
            document.getElementById("tweet")
        );
    </script>

</body>
</html>
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

+2

Javascript/Reactに詳しくないので、命知らずなコメントですが...

最近ちょうど似たような議論を見ました

teratail: Reactにおける関数の渡し方による動作の違い

上記のraccyさんの回答にあるthisの議論が参考になるように思います。

componentDidMount(){
  tweetsRef.on("value", function(snapshot){
    this.setState({
      tweets: snapshot.val()
    });
  });
}

functionの本体部分でthisを参照する際、この関数が

f.call(eventSource, snapShot)

と呼び出されるのであれば関数内のthisはeventSourceに束縛されますが、この場合はeventSourceがイベント発生元のインスタンス(tweetsRefの値)になるなら、thisは質問者さんが意図したものにならないのではないでしょうか。質問者さんの意図はthisがTweetContainerのインスタンスを表すことですよね?

対処:

class構文をお使いなので(ES2015前提なので)、functionによる無名関数ではなくアロー関数を使えば次のように書けると思います。

componentDidMount() {
  tweetsRef.on("value", snapshot => this.setState({
    tweets: snapshot.val()
  });
}

functionキーワードによる無名関数とアロー関数のthisの違いは次のような単純な例を見ると観察できます。無名関数はcallで起動される際の第一引数の値がthisに束縛されてから実行されますが、アロー関数はアロー関数が生成された時点の文脈でのthisが束縛されたクロージャーの元で実行されるので、callで起動されたとしてもその第一引数の値によりthisが変化することはないのだと思います。

function A() {
  this.a = 1;

  // 無名関数f本体のthisは関数生成時点のクロージャー内に束縛されて
  // おらず、f.call(x)で起動された際のxの値で(起動時に)束縛される。
  A.prototype.f = function () { return this.a; };
}

function B() {
  this.a = 1;

  // アロー関数本体のthisはアロー関数生成時点のクロージャー内に束縛される。
  B.prototype.f = () => this.a;
}

let a = new A();
let b = new B();
console.log(a.f.call({a: 2}); // 2
console.log(b.f.call({a: 2}); // 1

おかしな点がありましたら指摘いただけると幸いです。

投稿 2017/11/26 21:47

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/11/26 21:56

    KSwordOfHasteさん、ありがとうございます!

    実は先ほど解決したのですが、まさにおっしゃる通り、thisが親のコンポーネントを指定できていないことが原因でした。ご説明いただいたアロー関数を使うことにより、問題のエラーは起きなくなりました。

    componentDidMount(){
    tweetsRef.on("value", (snapshot) => {
    this.setState({
    tweets: snapshot.val()
    });
    });
    }

    かなりマイナーな質問にも関わらず、的確な回答をいただきありがとうございました。
    自分もまだまだReact.jsを始めたばかりなので、もっと勉強します。

    キャンセル

  • 2017/11/26 22:03

    自分もちょうど先日「なんでthisが思った通りにならないのだろう」としばらく悩んでいたのです。JSの落とし穴なのかも知れません。思い出してみると本サイトでも過去にそういう話が出てきてたと思いますが自分自身が充分その意味を掴めてなかったのだと思います。bindの意味とかようやく実感できました。

    キャンセル

  • 2017/11/27 03:47

    ES6かなんか、バージョンが変わって書き方が変わってたみたいですね。
    それまではthisをバインドしなくても勝手に認識してくれてたみたいなんですけど、それが自動じゃ無くなってたみたいです。
    React.jsは調べても古い書き方が多くて惑わされるので大変ですね...w

    キャンセル

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

ただいまの回答率

91.35%

関連した質問

  • 解決済

    React.jsを用いてラジオボタンで選択されている項目を取得

    現在、webアプリケーションの制作を行っており、React.jsを用いて、ラジオボタンで選択されている項目を取得したいと考えています。 以下のサイトを読んでみたのですが、ラジオボ

  • 解決済

    reactでkeyイベントを作成したい

    1,リスト操作する一番上位のメッセージコンポーネント MessageBox 2.リスト全体のメッセージコンポーネント MessageList 3.リスト1行のメッセージコンポー

  • 受付中

    この問題がわかりません

    ボックスに西暦年を入力し、[確認]をクリックすると、「〇〇大学が開校され てから xx 年です」と出力するページを作成せよ。「xx」は入力された西暦年 に応じて変化する。〇〇大学は

  • 解決済

    helloworldしたい

    以下のようなコードを手始めに書いたのですが、まったく動かず、アドバイスをいただけたらとおもいまうs。 <!DOCTYPE html> <html lang="ja"> <he

  • 解決済

    Onsen UIのアラートダイアログが反映されません!

    こんにちは、プログラミング初心者です。 Onsen UIの利用をこちらで皆さんに勧めていただいてから、Onsenについての基本事項は勉強しました。 現在、Monaca(HTML5+

  • 解決済

    Onsen UIのalert-dialogウィンドウをTextarea内の文字数制限超過時に表示した...

    こんにちは、プログラミング初心者です。 Onsen UIの利用をこちらで皆さんに勧めていただいてから、Onsenについての基本事項を同時進行で勉強しています。 現在、Monaca(

  • 解決済

    >>react<< 文字を表示できないエラー

    前提・実現したいこと このようなプログラミングを組みました。文字が表示されないエラーにあっています。babelというのを使っています 文字だけでなく、hrなどすら表示されず、戸惑っ

  • 解決済

    Slick.jsで左右逆方向にスクロールするカルーセルスライダーの設定方法

    図のイメージのようなことが実現したいです。 同一ページ内で、スライダー1とスライダー2がそれぞれ逆方向にautoplayでスクロールするカルーセルスライダーを作成したいで

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

  • JavaScript

    11222questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • React.js

    376questions

    A JavaScript library for building user interfaces

  • Firebase

    202questions

    Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。