2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Reactでcanvasを操作しても何も描画されない時はuseEffectのせいかも?

Posted at

canvasを使うプロジェクトに参加していて、デバッグ用のためにページの描画後に一回きり、空白のcanvasに対して図形を追加する処理を、useEffectにより実行しようとしました。しかし、画面上には何も表示されず、数時間を溶かしました。

TL;DR

useEffect上でcanvas操作をするには、レンダリングのタイミングと操作の順番に配慮する必要があることがわかった。

再現

期待したこと:とにかくなんでもいいから図形がcanvas上に描かれること
現実:何も表示されない

子コンポーネントのjsxの帰り値
return <>
  <canvas id='bar-canvas' />
</>
そのコンポーネント内でのcanvasのTSからの操作
useEffect(()=>{
    const canvas = document.getElementById('bar-canvas') as HTMLCanvasElement
    const ctx = canvas.getContext('2d')
    ctx.rect(10, 10, 150, 100);
    ctx.fill();
}, [])

問題の特定

  • console.logでcanvasの中身をロギング
    • オブジェクト自体は出力されるので正しく定義されていることを確認
  • Chrome DevToolsでタグがDOMに存在されることを確認
    • CSSプロパティも特に非表示にしている、などは確認できなかった
  • Canvasが何かに埋もれて隠れているのか?
    • useEffect内にCanvas画像をダウンロードするコードを挿入し、出力された画像を確認
    • 画像も空白だったので、この可能性はないと判断
canvasを画像としてダウンロードしてみる
    setTimeout(
      ()=>{
        const link = document.createElement('a');
        link.download = 'filename.png';
        link.href = (document.getElementById('bar-canvas') as HTMLCanvasElement ).toDataURL()
        link.click();
      }
      , 3000)
  • canvasをuseEffectで操作しているのが良くないのか?
    • useEffect内でのcanvas操作のコードをsetTimeoutでラップして時間を置いてからcanvas操作がされるようにした
    • 無事、画面に図形が描画された

問題の原因について考える

おそらくuseEffectの描画のタイミングの問題なのか?
GoogleでuseEffect canvas と検索すると、以下のSOの記事を発見した。

レンダリングのタイミングと、操作のタイミングの順番が大事なようだ。上の記事によると、これはuseEffect自体の問題ではなく、元のJavaScript/HTML自体が持つ特性に過ぎないとのこと。Reactを使うにせよ、使わないにせよ、レンダリングとcanvas操作のタイミングには注意すべきということだそうだ。

とはいえ、Reactではどう解決したらいいのか、ということは上の記事に書いているので、そちらを参照されたい。

自分の場合の解決法

自分の場合、useEffectを使っていたのは、デバッグのためだけであった。そもそもuseEffectで図形を表示するのではなく、特定のイベントがあったときに図形を表示する、ということが自分のやりたいことであって、そのイベントはコンポーネントの描画時から時間が経ってから発生するので、当面必要に迫られるまで解決しないことにしてuseEffectを削除する、というのが、解決法になった。

わからないときにどうすればいいのか?

経験上、何がわからないのがわからない、というときは、そもそも何らかのレイヤーの知識がごそっと抜けていることが多い。今回の例でいえば、useEffectとレンダリングのタイミングの関係や、canvasとレンダリングの関係などの知識が全くなかったので、そこに問題が生じていたという考え自体に至らなかった。

一つの視点:どんな仮説が立てられるか?

これは良くあるアプローチですが、これがうまく行くかどうかは、自分の知識に依存します。もし知識が初めからあるのであれば、仮説を立てて、順番に可能性を検証していくことが最短でしょう。しかし、そうでない場合には、全く先に進めないこともあります。

利用可能性ヒューリスティック

このような認知バイアスが人間にはあり、「利用可能性ヒューリスティック」と呼ばれています。自分に身近な知識が、可能性の列挙に影響してしまうということです。

では、どうすればいいのか、今回2時間以上浪費したので、自分なりに対策を考えました。それは、行き詰まったときには、自分の知識になるべく依存しないような視点を持つことです。

もう一つの視点:動いているコードから、自分が何を変更したのか?

今回は、 もともと動いていたコードの例を、自分でuseEffect内に挿入した、という差分がありました。 もしこのことを早く認識していれば、useEffect canvasとGoogle検索して、最短で答えに辿り着いたかもしれません。特に、今回のような「エラーは出ないけど、期待通りに動かない」という、情報が少ない場合は、自分が何をしでかしたのか、を理解することが、唯一の情報源になる気がします。

行き詰まった時は、VSCodeの機能で差分でも眺めてみてはいかがでしょうか?

それでは、ごきげんよう!

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?