yn2011's blog

技術メモ

Rules of Hooksに違反していないのにHooks can only be called inside the body of a function componentエラーにハマった話

環境

  • react 16.8.2
  • webpack 4.29.3

事象

  • webpack-dev-sereverで、Hooksを利用した下記のコードを実行するとHooks can only be called inside the body of a function componentエラーが発生

再現手順

  • 問題のコード(イメージ)
// ./App/index.tsx

import * as React from 'react';

const App = () => {
  const hooks = React.useState('hoge');

  return <span>hoge</span>;
};

export default App;
// ./index.tsx

import * as React from 'react';
import * as ReactDOM from 'react-dom';

import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));
<!-- ./index.html -->
<html>
  <body>
    <div id="root"></div>
    <script src="bundle.js"></script>
  </body>
</html>
  • webpack-dev-serverを利用してindex.htmlを開くとUncaught Invariant Violation: Hooks can only be called inside the body of a function componentエラー

    • 単純にビルドだけして開いてみたら発生しなかった(webpack-dev-serverが怪しい...?)
  • エラー自体はHooksの呼び出し位置が適切できないといった内容のようだが、この場合は特にそんなことはない(詳細はRules of Hooks参照)

  • こんなシンプルな構成なのになんで? 何が起きてる?

HtmlWebpackPluginのhtmlテンプレートが原因

  • 自分の環境ではwebpack-dev-serverを利用する際に HtmlWebpackPluginを使って動的にhtmlファイルを出力していた
  • なので、上記のindex.htmlをそのまま利用しているわけではなく、htmlテンプレートとして使っていた
  • おもむろにindex.htmlをブラウザで開いてみたら...
<html>
  <body>
    <div id="root"></div>
    <script src="bundle.js"></script>
    <script src="bundle.js"></script>
  </body>
</html>
  • このようにバンドルされたjsファイルへの参照が自動挿入されて2つになっていた

    • (webpack-dev-serverを利用しない時は上記のhtmlを使用しないので再現しなかった)
  • ひとまずhtmlテンプレートを修正したらエラーを吐かなくなって一安心

ReactDOM.renderを2回呼び出すとどうなるか

If the React element was previously rendered into container, this will perform an update on it and only mutate the DOM as necessary to reflect the latest React element.

ReactDOM – Reactより引用

  • ただしFunction Componentのrenderメソッド相当(返り値)以外の部分は普通に実行されるのでReact.useState('hoge')が2度評価されたことが原因っぽいなあと予想
  • しかし、ReactDOM.renderを2回続けて呼び出すコードを実行しても再現しなかった
  • ReactDOM.renderというよりbundle.jsを2回読み込んでいることが影響しているのかも
  • Hooks使わないコードだとエラーが発生しないので今までhtmlテンプレートに問題があることに気づけなかった...

VSCodeでTypeScriptを書くときに役立った拡張機能まとめ

1~2週間ほどVSCodeでTypeScript(+React)を書いていたので、その際に役に立った拡張機能をまとめ。

環境

TypeScript Importer

  • TypeScript Importer - Visual Studio Marketplace
  • 未インポートのモジュールを利用してコードを書き始めると自動的にインポートの宣言文を挿入してくれる
    • ただし、たまに意図しない動作をしたり、あるいは動作を期待していたら動作しなかったりすることがある気がする
  • VSCodeのコマンドパレットからAdd Importを実行すると、インポートするモジュールを選べる
    • 自分でインポートの宣言文を書く気にはなれないのでこれがけっこう便利

TypeScript Import Sorter

  • TypeScript Import Sorter - Visual Studio Marketplace
  • VSCodeのコマンドパレットからSort Importsを実行して、インポートの宣言文をソートできる
  • 設定すればファイル保存時に自動的ソートすることもできて便利("importSorter.generalConfiguration.sortOnBeforeSave": true

Move TS

Prettier

  • Prettier - Code formatter - Visual Studio Marketplace
  • コード整形。使ってみると、これなしの開発は考えられなくなる
  • 自分は元々使っていて、TypeScriptファイル保存時にもPrettierが自動的に実行されるように設定した

ES7 React/Redux/GraphQL/React-Native snippets

その他

  • lintについては、今後はTSLintではなくESLintがTypeScript対応を進めるという発表があり( TypeScript Roadmap: January - June 2019 · Issue #29288 · Microsoft/TypeScript · GitHub)しばらくは手を出さなくていいかなと思ってる
  • 自分は、ES5のコードベースでもPrettierを使うならESLintはno-unused-varとかno-unreachableぐらいで十分だと思っていて、TypeScriptについてはVSCodeが最低限の警告を出してくれる(no-unreachableは警告してくれないみたいだけど)のであまり困っていないというのもある

まとめ

  • そういうわけでTypeScript書いていきましょう

"Java 8 is required to run..."エラーが表示されVSCodeでApexのシンボル情報を参照できなくなった場合の対応

環境

事象

  • なぜかVSCodeでApexのシンボル情報を参照できなくなった(とても開発効率が落ちる

    • ↓これが出なくなった
      f:id:pokuwagata:20190123223417p:plain
      Apex(VSCode拡張)の詳細ページから引用
    • ついでにサイドバーのアウトラインも表示されなくなった
  • VSCode起動時にJava 8 is required to run. Download and install it from https://java.com/en/download/.というエラーが表示されるようになった

Java11が原因?

forcedotcom/salesforcedx-vscodeにissueが起票されていた github.com - Apex Language Server · forcedotcom/salesforcedx-vscode Wiki · GitHubに書いている通りにsalesforcedx-vscode-apex.java.homeにJava8用のパスを設定したら直った

  • $ java --versionしたらJava11.0.2だった
    • VSCode拡張のApexはJava8のみ対応とのことだった
  • 特に環境を更新した記憶はないけど、知らない内にJava11がインストールされていた...?

文字からUTF-8のバイトコードを調べるワンライナー

環境

文字からUTF-8バイトコードを調べるワンライナー

  • (全角ハイフン)を調べたい場合
$ echo -n 'ー' | iconv -f utf-8 | xxd -p
e383bc
  • -tを明示しない場合はUTF-8で出力と解釈される

ワンライナーの意味

出力するエンコーディング方式を指定する

$ echo -n 'ー' | iconv -f utf-8 -t utf-16 | xxd -p
feff30fc
$ echo -n 'ー' | iconv -f utf-8 -t sjis | xxd -p
815b

他の方法は

  • あるかもしれないです

楽々ERDレッスンでER図の描き方を学んだ

f:id:pokuwagata:20190108100308p:plain:w500

tl;dr

  • 楽々ERDレッスン+MySQL WorkbenchでER図を描く練習が捗る

取り組む前の自分のスキル・知識

  • 業務でER図を読むことはある
  • 業務でER図を描いたことはない
  • IE記法は分かる、IDEF1X記法は分からない

動機

  • 最近、実装より上のレイヤーの設計に関わる機会が増えた
    • ER図がないとデータ構造を議論しにくい(ER図がない場合は自分で描けるようにしたい)
    • ER図がないと自分もデータ構造を理解できない・問題に気づけない・忘れると思い出すのに時間がかかる
  • というわけでER図を描く訓練したい

楽々ERDレッスンとは

...それに加えて、私が設計のスキルを付けるために実際に行ってきた「身の回りのものを題材にERDを書く」という方法のサンプルを今回は8種類書き下ろさせていただきました。手前味噌ではありますが、本書をお読みいただき実践していただくことで「実務で具体的に手が動く」というレベルに達していただけると考えています。

楽々ERDレッスン(羽生章洋)|翔泳社の本より引用

  • ER図の演習問題と解答・解説が8セットも掲載されている
    • 題材の例としてはレシート、注文書、請求書等
    • 演習問題は全体の1/3ぐらいで、DBの論理設計周りの解説もあり
  • 何事も手を動かすことは正義

どうやってER図を描くか

  • MySQL :: MySQL Workbench: ビジュアルデータベース設計を使った
  • ツールはあくまで手段なので、学習コストの低さと描きやすさがそれなりに両立していれば良いと思った
  • 多少動きに癖はあるが、練習用・イメージを掴むのに使うのに丁度よいと感じた
  • ER図からテーブル定義のDML発行可能

8回分完走してみて

所感

  • 年末年始でコツコツ8回分進めた(内7回分のER図を実際に描いた)
  • 答えの図だけでなく、始めにイベント系、次にリソース系のエンティティを見つけて項目を足してリレーションを考えて...という一定の型に沿った解説が凄く良かった
  • (規模にもよるが)慣れれば一旦議論の場に出せるレベルのER図を描くのは難しくない。ツールに慣れていれば長くても30分ぐらいでできるタスクだと思った
    • 作図のための型があったので、1,2回解説を読んで描いたら後の回は大体自力で描けて大体合ってた
    • やっぱり図にすると業務の理解不足、考慮漏れが明らかになるので絶対描いたほうが良いと思った
  • IDEF1X記法が解答や例で使われていたので少し馴染めた(MySQL Workbenchが両方の記法を切り替えできたのも良かった)
  • あと掲載されている題材の画像がもっと大きいと良いなと思ったりもした(文字が細かくて読みにくい)

苦手意識

ER図を描いていて気づいた自分の弱点

  • イベントを中心にリソースとリレーションを繋ぐ発想が浮かびにくかった
    • (例)何となくUserテーブルの項目が多くなりがちだった
  • 帳票等のサンプルからイベントを見つける/切り分けるという業務分析の考え方や経験が足りないなと思った
    • (例)図書館の予約(リクエスト)申込書が、1つの紙面に予約と置いていない本のリクエストという2つの役割を担っている等
    • これはありがちで、設計が難しくなるパターンの1つだという実感がある

次は

  • 練習したのはあくまで架空のシステムのER図なので、あとは実際に稼働している多くのシステムと対峙して経験を積んでいくかという気持ち
  • 要件定義系の演習課題集も何冊か発売されているみたいなので少し興味ある

macOS 10.14でdark mode有効時にMySQL WorkbenchのUIが変になる問題の解決策

楽々ERDレッスン(羽生章洋)|翔泳社の本を読みながらER図を描きたかったので、MySQL Workbenchがいいかなと思いセットアップしていたら困ったのでメモ。

環境

事象

f:id:pokuwagata:20190101202524p:plain

解決策

$ defaults write com.oracle.workbench.MySQLWorkbench NSRequiresAquaSystemAppearance -bool yes

結果

f:id:pokuwagata:20190101202822p:plain

  • 直った
  • 8.0.14で修正されるらしいのでアップデート待ち

bashの`printf "%.s" hoge`と`printf "%0s" hoge`の違い

環境

事象

$ printf "%0s" hoge
hoge

$ printf "%.s" hoge
# 何も表示されない

疑問

  • 文字列かつ精度指定は文字数の制限なので0を指定したら何も表示されないのでは
    • "%.s"で何も表示されないのはピリオド=精度0と解釈されているからだと思う

オプションである精度は、ピリオド ('.') とそれに続く10進数という 形式で指定する (10進数はオプション) 。 10進数の文字列の代わりに "" や "m$" (m は 10 進整数)を書くこともできる。 "" と "m$" はそれぞれ、次の引き数と m 番目の引き数を精度として 使うことを指定する (これらの引き数は int 型でなければならない)。 精度として '.' だけが指定された場合、 精度はゼロとみなされる。 精度が負の数だった場合、 精度は指定されなかったものとみなされる。 d, i, o, u, x, X 変換では、表示される最小の桁数を指定する。 a, A, e, E, f, F 変換では、小数点以下に表示される数字の桁数を指定する。 g と G 変換では、有効数字の最大桁数を指定する。 s と S 変換では、文字列から出力される最大文字数を指定する。

Man page of PRINTFより引用

解決

  • 文字列の場合は%5.3sは全体5桁、最大3桁の文字列を出力する
$ printf "%5.3s" 123456
  123 # 全体の長さが5なので半角空白が2つ入る
  • したがって、%.s%0.0sと解釈されて最大0桁の文字列出力だから何も表示されなかった(推測)*1
$ printf "%0.0s" hoge
# 何も表示されない
  • ちなみに、%0sで表示されたのは最大桁の指定無しだったから(推測)
    • 全体の文字数<引数の文字数の場合は全て表示
$ printf "%1s" hoge
hoge

精度は変換指定子によって意味が異なる

  • 何となく%fで小数点以下を指定するイメージしかなかった
  • ちゃんと確認しよう

これがしたかった

  • そもそもなんで気になっていたかというと、このスクリプトの原理が分からなかったからでした
$ printf hoge\\n"%.s" {1..5}
hoge
hoge
hoge
hoge
hoge

参考

*1:実装は確認していないので