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

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

新規登録して質問してみよう
ただいま回答率
85.48%
JavaScript

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

React.js

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

Q&A

解決済

3回答

345閲覧

setIntervalに指定する値について。

nezpapapa

総合スコア9

JavaScript

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

React.js

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

0グッド

0クリップ

投稿2018/08/11 20:53

前提・実現したいこと

https://reactjs.org/docs/state-and-lifecycle.html
こちらのサイトを見て勉強しているときに、不思議に感じたことがあったので質問しました。

該当のソースコード

こちらのサイトに書かれている下のソースコードで、componentDidMountメソッドのsetIntervalの中身を

this.timerID = setInterval(this.tick, 1000);

としたときに動かない理由はなんでしょうか?
私としては、このようにすればメソッドの内容が展開され、うまく動くだろうと思ったのですが...。

javascript

1class Clock extends React.Component { 2 constructor(props) { 3 super(props); 4 this.state = {date: new Date()}; 5 } 6 7 componentDidMount() { 8 this.timerID = setInterval( 9 () => this.tick(), 10 1000 11 ); 12 } 13 14 componentWillUnmount() { 15 clearInterval(this.timerID); 16 } 17 18 tick() { 19 this.setState({ 20 date: new Date() 21 }); 22 } 23 24 render() { 25 return ( 26 <div> 27 <h1>Hello, world!</h1> 28 <h2>It is {this.state.date.toLocaleTimeString()}.</h2> 29 </div> 30 ); 31 } 32} 33 34ReactDOM.render( 35 <Clock />, 36 document.getElementById('root') 37);

補足情報(FW/ツールのバージョンなど)

React, ReactDOM最新バージョン。

ご教授、よろしくお願いします。

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

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

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

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

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

jun68ykt

2018/08/11 23:17 編集

※さきほど、こちらからご質問に挙げられている Clock の動作確認を書きましたが、質問の趣旨を誤読していたので消去しました。
guest

回答3

0

ベストアンサー

簡易コード

原因にフォーカスして、簡単なサンプルコードを書きます。

JavaScript

1'use strict'; 2class Foo { 3 constructor (a) { 4 this.a = a; 5 } 6 bar () { 7 console.log(this.a); 8 } 9} 10 11var foo = new Foo(2); 12var bar = foo.bar; 13 14foo.bar(); // 2 15bar(); // TypeError: Cannot read property 'a' of undefined

関数コード内の this 値は関数呼び出した時に決定します。
foo.bar() 呼び出しされると、this値は「fooに束縛」されます。
bar() 呼び出しは、特別な呼び出し方法ではない為、this値は規定値(Strict Mode なら、undefined)になります。

setInterval

JavaScript

1this.timerID = setInterval(this.tick, 1000);

setInterval の第一引数はコールバック関数です。
コールバック関数は変数に代入されて、後で呼び出されるのと同じ扱いになる為、this 値は規定値となります。
しかし、setInterval には第一引数となる関数のthis値を window に束縛する規定がある為、this 値は window になります。

Re: nezpapapa さん

投稿2018/08/12 00:58

think49

総合スコア18162

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

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

nezpapapa

2018/08/12 18:09

>関数コード内の this 値は関数呼び出した時に決定します。 >foo.bar() 呼び出しされると、this値は「fooに束縛」されます。 >bar() 呼び出しは、特別な呼び出し方法ではない為、...。 thisには、通常の関数呼び出しではundefinedが、それ以外では呼び出し側のオブジェクトが設定される、と考えていいということ...ですかね。 回答に書いていただいた、setIntervalの動きのような、例外的なパターンの動作を理解したり、覚えたりするのが大変そうだな、と感じました。 他の方の回答や、ネット上の資料を読んで出来る限り例外的なパターンについても知っておこうと思います。 ご回答ありがとうございました!
guest

0

こんにちは。
コンストラクターの処理に this.tick = this.tick.bind(this); を追加して、以下

javascript

1constructor(props) { 2 super(props); 3 this.state = {date: new Date()}; 4 this.tick = this.tick.bind(this); 5}

のようにすることによって、

javascript

1this.timerID = setInterval(this.tick, 1000);

が意図通り動作します。

以下、this.tick = this.tick.bind(this);が必要な理由です。これを追加しないと、

javascript

1 tick() { 2 this.setState({ 3 date: new Date() 4 }); 5 }

this.setState()this はグローバルオブジェクトを参照し、ブラウザで実行されるならば window になります。windowには setStateというメソッドはないので、

Uncaught TypeError: this.setState is not a function at tick

というエラーになってしまいます。

上記について、(英語ですが)以下の記事が分かりやすいです。

以上、参考になれば幸いです。


追記

以下も参考になるかもしれません。

投稿2018/08/11 23:04

編集2018/08/12 00:36
jun68ykt

総合スコア9058

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

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

nezpapapa

2018/08/12 18:09

>this.setState() の this はグローバルオブジェクトを参照し、ブラウザで実行されるならば window になります。 他の回答を読んで、「this.tickはsetIntervalの中で展開されて、普通の関数呼び出しと同じように実行されるから、thisはundefinedになる。しかし、setIntervalの中でthisはwindowになるから、このような動きになる」のだと理解しました。 回答に載せていただいた、一つ目のリンク先でもそういう雰囲気のことを言いたいのかな、と思っています。 二つ目のサイトでは、アロー関数を使いthisを束縛(?)する方法を紹介しているようですね。 Babelを使って、メソッド定義を比較しているところの、普通のメソッド定義という部分のソースコードは理解できませんでしたが、記事全体としては、一つ目のサイトを読んでいたおかげで納得できました。 三つ目のサイトは、上で読んだ記事に加えて、いくつか別の解決策が載っているようですね。 ただ、私の英語読解能力では意味が理解できないのが残念です。 また、Proxyオブジェクトなど、いくつか知らないものが出てきたのでこれも調べておこうと思います。 ご回答ありがとうございました!
guest

0

ES6 の React メソッドは明示的に束縛しなくてはいけません。
constructor() を次のようにしてください。

js

1constructor(props) { 2 super(props); 3 this.state = { 4 date: new Date() 5 }; 6 this.tick = this.tick.bind(this); 7}

投稿2018/08/11 22:16

編集2018/08/11 23:16
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

nezpapapa

2018/08/12 18:09

thisがClockクラスではなく、他のオブジェクトを指してしまうことが原因だったんですね。 thisを束縛する方法も色々あるようで、とても勉強になりました。 ご回答ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問