Webエンジニアの備忘録

およそ自己の作業メモとして残しております。

componentWillMountをReactフックで書く方法を考えた

componentWillMountの今…

v16以前、componentWillMountというライフサイクルイベントがありました。(過去形…)
v17以降は非推奨となり、UNSAFE_componentWillMount と名称変更されています。

嫌われるcomponentWillMount

v16以前からReactを利用しているプロジェクトではしばしばReactフックへの移行の話が上がり、componentWillMountの対応方法について求めるコメントが上がっています。ただし、解決方法については有識者からは冴えない返答が散見されます。

  • Reactフックを使えばconstructorはいらないよ!
  • useEffectを使えばcomponentDidMount相応の挙動だ。(ただしレンダー後に実行)
  • そもそもcomponentWillMountを使うな。

言い回しは変わっていますが、すべて3つ目の「使うな」の言い換えになっています。
有識者側の言い分としては、実装を無くすよう検討してくれということなのです。

非推奨な理由を考察

そもそもComponentのレンダー前にやっている処理はComponentに関係ない処理である可能性が高いです。
何かしら計算が必要であれば計算後の値をpropsに送ればよいし、レンダーに関わる処理はComponent呼び出し前に済まされているのが理想的です。

おそらく、v16以前はすべてをComponentで行う志向が強く、ライフサイクルにすべての処理を内包するのが作法だったかのように思えます。
(本当はもっと前からですが)v17ではパラダイムシフトが起きており、債務を絞った、より軽微なComponentを目指すのがトレンドになってきました。

非推奨でも使いたい

設計思想の変化は理解しつつも、すでに動いているサービスの改修は別問題です。 useMemoを利用するのがシンプルかと思います。

const Componnet = ({ updateTrigger }) => {
  const key = useMemo(() => {
    // ここに前処理を書ける
    return updateTrigger;
  }, [updateTrigger]);

  return (
    <div key={key} />
  );
};

値を返す特性上、レンダリングより早く動作し、propsを外部更新のトリガーにすればcomponentWillUpdateの代替としても利用できます。 本当に初期実行時にしか動作しないのであれば、useStateを実行済みフラグなどとして利用する手段も浮かびましたが、こちらのほうがキレイかと思いました。


フィードバックなどあれば、コメントいただければ嬉しいです!

実機へのXcodeビルドが失敗したときに振り返ること

失敗は突如として起こる…

iOSのビルドが通らない、実機がつながらないなどにぶち当たり、一日潰してしまった…などということはないでしょうか? 残念ながら、わたしは多々あります

起きるタイミングは?

コードが影響であれば、gitで切り戻したり、差分をstashすることで変更前を試せます。 それ以外では傾向として、XcodeOSXMac)・iOSなどのアップデートをトリガーにすることが多いかと思います。

Xcodeに関しては開発作業前の対応が多く、OSXについてもXcodeとセットでの更新なので気づきやすいです。 ですが、iOSアップデートについては完全に意識から抜けていることが多いので、注意が必要!

  • iOSのバージョンがビルドターゲットから外れていないか確認
    • Xcodeの更新等で改善する可能性あり

iPhoneが認識されない?

バイスが待てど暮らせど出ないと、ケーブルの断線など疑ってしまいがちです… ケーブルを2本も用意しておけば、この手の懸念はすぐに払拭できます。

さらにiPhoneのロック解除をしてみましょう。

  • PCを信頼するか否か、ダイアログが出ている場合があります…
    • 信頼するを選択すると出てきます。

Signingに関わるところは?

Signingの警告が消えないときがしばしばあります。 証明書にまつわる事象ですが、ローカルだけでなくApple Developerサイト側で対応が必要なケースがあるので注意が必要です。

  • Certificatesの有効期限が切れていないか?
  • Certificatesを参照可能なチームからはずれていないか?
  • Devicesに実機のUDIDが登録されているか?
  • ProfilesのDevicesにチェックは入っているか?

ローカル側でも設定を引けない原因となる可能性があります。

  • Preferences > Accounts にAppleIDが登録されているか?
  • KeychainにCertificatesファイルは登録されているか?

最近引っかかったのですが、Targetが複数あるプロジェクトだとビルド対象以外のTargetでSigningの警告がでていてもビルドできないケースがありました。

  • すべてのTargetのSIgningが通っているか?

今後もこちらに知見を積んで行こうと思います。

Macbookを購入して最初にやること(メモ)

このページの内容

7年ぶりに新しいMacbookを購入しました! セットアップは非常に楽しい作業ですが、抜け漏れないようにやりたいので自分に向けてメモを残します。

手順

開梱・起動する。

  • 落ち着いて開ける。広めのデスクとコンセントを確保する。
  • Apple IDを入力する。(パスワードを思い出しておく)
  • Macbookのパスワード設定・指紋認証までしておく。

インストール

  • 何はともあれ、Xcodeをインストール。
    • ダウンロードに時間がかかるため。command line toolsなど考えると必須。
  • Chromeをインストール。
  • Google日本語入力をインストール。
  • VSCodeをインストール。
    • Extension: Setting Sync を入れて設定を引っ張り出しておく。
  • iTerm2をインストール。

システム環境設定

Dock: 右

キーボード: キーリピートを最速にする。 f:id:tak_taniguchi:20200406223502p:plain

キーボード: スリープのショートカットを作成しておく。 f:id:tak_taniguchi:20200406223506p:plain

キーボード: Google日本語入力を入れる。 f:id:tak_taniguchi:20200406223702p:plain

ディスプレイ: 解像度を最高にする。 f:id:tak_taniguchi:20200406223831p:plain

CUI環境

  • 古い端末から以下をコピーしてくる。
  • プロンプトを見慣れた感じにする。
$ cp /etc/zshrc ~/.zshrc
$ chmod 600 .zshrc
$ vi .zshrc
  :
PS1="[%n@%m %1~ ]%# "
  :
  • ssh github.com を通しておく。
  • ssh bitbucket.org も通しておく。

キャプチャをJPEGに切り替える

OS標準のスクリーンキャプチャをPNGJPEG保存に切り替えます。(容量が大きいので…)

% defaults write com.apple.screencapture type jpg

また作業が進んだら書き足します。

自社プロジェクトに xcprojectlint をかけてみた

知見が少なかったり、検証者がいなかったり、小さな開発現場は積極的にLinterを入れるべきだと思っています。

iOS開発をはじめてまだ1ヶ月ちょっとですが、まず最初にLinterを探しました。

プロジェクトのLinterを発見

引き継ぎプロジェクトが Objective-C だったのですが、言語のLinterは良さそうなものが見つからず、代わりにプロジェクトのLinterを見つけました。

github.com

アメックスさんがオープンソースを公開しているとは知りませんでした。 こちらはSwiftで書かれておりMacでの導入も非常に簡潔で、さくっと仕掛けられました。

導入方法について

何人かの方がすでに書かれていたので、記事を拝見させていただきました。 こちらで事足りると思いますので割愛します。

qiita.com techblog.lclco.com

実行

今回は業務上引き継いだおよそ4年もののプロジェクトにて検証をかけます。 ただし会社のコードはさらせないので、エラー、キャプチャ等のサンプルは比較的リアルな再現と思ってください(笑)

./xcprojectlint --report error --validations all --project awesome.xcodeproj

結果

初回実行で 219項目 もの指摘をされました…これは心が折れます\(^o^)/

検査対象である xcodeproj の中身はそもそもテキストエディタではあまり扱わない場所なため、解決には骨が折れました…(^_^;)

問題を分類するため、以下のような手順に切り替えました。

対応

チェックの際、 オプションを刻む実行 に切り替えました。

f:id:tak_taniguchi:20181117123520p:plain

xcprojectlint は5つ内容をチェックしてくれます。 初回実行では --validations all で実行してしまったのですべての検証が行われました。

以下の順序に切り替えます。

1. empty-groups

空のグループを検出してくれます。こちらも不要なものは削除していきます。 一番わかり易いのでこちらから対応しました。

error: Xcode folder “awesome/samples” has no children.

2. items-in-alpha-order

ファイルの並び順がフォルダ・ファイルのアルファベット順であることをチェックします。

error: Xcode folder “awesome/controllers” has out-of-order children.
Expected: ["comment", "friend", "game", "menu", "shared"]
Actual:   ["shared", "comment", "menu", "game", "friend"]

Expected があるべき並び方となっていますが、Xcodeのソートを利用するとフォルダ・ファイルを区別せずに名前順になります。ここは若干手作業が必要になりました。

f:id:tak_taniguchi:20181117112535p:plain

3. files-exist-on-disk

実ファイルが存在しないものを教えてくれます。ナビゲータ上でレファレンスが赤字になっている箇所ですね。こちらはリファレンスを消していくことで解消します。

New type found: ["versionGroupType": wrapper.xcdatamodel, "path": awesome.xcdatamodeld, "isa": XCVersionGroup, "sourceTree": <group>, "children": <__NSArrayM 0x1234567890A>(
1234567890ASDFGHJKLQWER
)
, "currentVersion": 1234567890ASDFGHJKLQWER]

イニシャルコミットで作られたものの、利用されずにファイルだけ消されたような形跡がいくつかありました。

4. disk-layout-matches-project

実ファイルの所在とナビゲータの配置がマッチしているか確認してくれます。 先頭にどのファイル名、フォルダ名が表示されますが、パスは表示されないのでこちらも少し頑張って検索しながら調整していく感じです(^_^;)

error: File “TopViewController.m” (1234567890ASDFGHJKLQWER) is misplaced on disk, or wrong kind of reference.
error: Folder “items” (1234567890ASDFGHJKLQWER) is misplaced on disk, or wrong kind of reference.

また、Xcodeのフォルダとグループは似て非なるもので、内包する実体との関係が少し変わってくるようです。グループが正しく設定されていない箇所を指摘されます。

グループについてはLocationにて相対グループに統一し、フォルダアイコンから実ファイルの相対パスを設定することで、ナビゲータ上のファイル移動に実ファイルも対応されるようになりました。

f:id:tak_taniguchi:20181117114501p:plain

5. build-settings-externalized

こちらが最後で最難関でした。 ビルド設定は project.pbxproj ではなく、個別ファイル(xcconfig)で管理されるのが望ましいようですが、こちらはまだ徹底できていません。

/Users/ttaniguchi/work/awesome/awesome.xcodeproj/project.pbxproj:2134: error: Pods-awesome.development.xcconfig (development) has settings defined in the project file.

なんとか5ステップを通して、8〜9割がたはLinterを通すことができました。 作業を通してナビゲータの整頓方法や、グループ、ファイルの差異、プロジェクト設定関連のファイルレイアウトを理解することができました。

Linter はこのあたりを読み解くきっかけとしても実行してみてよかったです。

iOS開発の事始め

今まで近くて遠い存在だったiOS開発ですが、ひょんな事から先月より自社アプリの主担当に就任し、突貫で技術習得しました。 「ピンチはチャンス」 、この1ヶ月は会社の理解もあり引き継ぎ名目で集中してインプットができました。

ここで1ヶ月を振り返り、覚えたことをメモがてら記録しておこうと思います。

やったこと

Xcodeの使い方を学ぶ 

ウィンドウ名称の把握

まずは各ウィンドウの名称を把握し、ググれる準備からです(^_^;)

【アプリ開発】Xcodeのウィンドウ名称 | Fussan Blog

こちらのサイトなど、参考にさせていただきました。 また、書籍でいくつかのXcodeバージョンのキャプチャなども確認しました。

ファイルタイプの把握

利用されているファイルの種類についても少しまとめました。

  • .xcodeproject: Xcodeプロジェクト。実体はディレクトリで存在する。
  • .xcworkspace: XcodeワークスペースPods利用など、プロジェクトが複数になるときに利用。
  • .plist: プロパティリスト。内部的にはxmlで記載される、おもに設定ファイル。
  • .h: Objective-Cヘッダーファイル。
  • .m: Objective-Cメインファイル。今回の主戦場。
  • .swift: Swiftファイル。残念ながら当該のプロジェクトではほぼ取扱なし…
  • .xib: XML Interface Builderファイル。単ページのテンプレートフォーマット。
  • .storyboad: Storyboadファイル。画面遷移を可視化できる新テンプレートフォーマット。
    • xibからstoryboadへの完全移行も共存も可能。
  • .xcassets: アセットカタログ。ディレクトリ構造のファイル群を contents.json を用いてカタログ管理している。

エディタの把握

Xcodeを使った最初の違和感は、ツールを触った際に出てくる git差分 でした。どの操作がどのコードに影響を与えているのかが、序盤の肝となりました。

ナビゲータ/プロジェクトエディター

ナビゲータの ファイルツリーは実ファイルの配置と異なります 。こちらは [プロジェクト名].xcodeproj 下の project.pbxproj で管理されており、ファイルの並び順が変わった際にもコードが書き換えられます。

ナビゲータツリーのルートをクリックすると、プロジェクトやターゲットの設定(下図)が確認できますが、こちらも [プロジェクト名].xcodeproj 下のxml等に対する書き出しを行っています。

f:id:tak_taniguchi:20181117003951p:plain

なので、意図する書き換え以外で [プロジェクト名].xcodeproj 下に差分が出た際はマウス操作等による可能性もあり、ちょくちょくコミットから外しています。

アプリ起点について

コードリーディングに際して真っ先に気にする起点についてもこちらに設定がありました。Main Interface を用いて起点となる Storyboard が選べるようです。

f:id:tak_taniguchi:20181117020342p:plain

とはいえ、 AppDelegate.m も起動時に実行されるので、こちらでインスタンス生成しても良さそうです。

インターフェイスビルダー/ストーリーボード

xib/storyboard を開いた際はこれらのエディタが起動しています。こちらもXcodeのバージョンアップでオプションの追加などが発生し、ときおり意図せずコードが勝手に書き換わるケースがあります。

アセットカタログ

xcassets は実ファイルが json で存在するのですが、画像をサイズで括って管理するのに便利です。旧仕様だとおそらくファイル名に hoge@2x.png などと節尾句を設けるのがセオリーだったようですが、こちらのほうが一覧性もあるので、追々完全移行する予定です。 唯一、多言語対応の考慮がされていないのが難ありです。

f:id:tak_taniguchi:20181117011307p:plain

Objective-Cを学ぶ

ネット上の記事やブログはSwiftに席巻されていて、Objective-Cについてはあまり残っていませんでした。こちらは書籍を購入し体系的に学習中です。

詳解 Objective-C 2.0 第3版

詳解 Objective-C 2.0 第3版

NSLog(@"test");

最初に学ぶべきはどの言語でもダンプでしょう。わたしはそのほうが捗ります。

  • コード実行箇所のあたりを付けて、ブレイクポイントで確認。
  • ダンプで細かな値なども確認。

これで実動を踏まえたコードリーディングが可能です。 ひとまずObjective-Cはこれを利用して読み解いていく予定です。

ライブラリ管理を学ぶ

CocoaPodsの把握

iOS開発ではCocoaPodsというパッケージ管理ツールを用いるようです。

CocoaPods.org

こちらを扱い始めると、実プロジェクトと別に Pods プロジェクトが併設されます。それによって、Xcode起動直後に開くファイルが xcodeproject から xcworkspace に変わります。

xcodeproject を開いてビルドしようとすると、 Libraryが見つからない という内容のエラーに苦しみます…(苦しんだ)

f:id:tak_taniguchi:20181117015217p:plain


インプットが多く纏めきれませんでしたが、俯瞰的にこんな感じで情報収集をしていました。次はもう少し絞り込んで、メモを残そうと思います。

getUserMedia() でカメラ・マイクのブロックを個々に検知

最近詰まったので、メモっておくことにします。

ブロックによるエラーの特徴

ブラウザから getUserMedia() を用いてカメラやマイクにアクセスすると、それらのデバイスへのアクセス許可が必要になります。これがブロック状態であった時に NotAllowedError が飛んで来ます。 ただし、カメラ・マイクともにアクセスを求めた際、どちらかが利用できる状況であればブロックエラーが取得できません。

navigator.mediaDevices.getUserMedia({ audio: true, video: true })
  .then((stream) => {
    this.setState({ stream });
  .catch(err => console.log(err)); // カメラ・マイクともにブロックの場合のみ NotAllowedError を受け取る

上記のブロックを受けた場合は音声のみの動画、または音声のない動画が取得出来ます。これはこれで、プライバシーを尊重したブロックの結果なのですが、開発都合で個々のブロックをキャッチしたいケースが多々あると思います。

対応策

以下のコードが対応策を施したものです。 stream を取得したい getUserMedia を実行した後に、 マイクのみ、カメラのみの getUserMedia を実行することで、こちらが NotAllowedError エラーを取得してくれます。

navigator.mediaDevices.getUserMedia({ audio: true, video: true })
  .then((stream) => {
    this.setState({ stream });

    // マイク単体検証(ブロック有無)
    navigator.mediaDevices.getUserMedia({ audio: true })
      .then(streamTmp => streamTmp.stop())
      .catch(err => console.log(err));

    // カメラ単体検証(ブロック有無)
    navigator.mediaDevices.getUserMedia({ video: true })
      .then(streamTmp => streamTmp.stop())
      .catch(err => console.log(err));
  })
  .catch(err => console.log(err));

getUserMediaを連投して大丈夫かな、という懸念はありましたが、Android数端末、Windows等で確認したところ問題は見られませんでした。 ただ個別チェックに利用した stream は取得後すぐに止めています。( streamTmp.stop()

所感

急場しのぎではありましたが、比較的シンプルに対処ができてよかったです。 それでも、これより良い解決方法などありましたらご享受いただければ幸いです。コメントなどください。

2017年を振り返る

自身の来年やるべきことを模索するためにメモを残しています。

所感

昨年にクライアントサイドに転向し、主にブラウザ対応に重きをおく開発をおこなっていました。サーバーサイドでもRailsなど新しい経験もしましたが、Javascriptの世界は作法も大きく異なり、エンジニアリングの世界が格段に広がりました。

やったこと

Reactjs

クライアントサイドの学習基盤としてReactjs+Reduxに触れられたのは非常に良かったです。APIを通してデータを取得するフローや、特に非同期の考え方はクライアントの動きを深く知ることができました。 コンポーネントのライフサイクルはネイティブにも通じる考え方で、今後はiOSAndroidの開発にも触れてみたいと思っています。

Ruby / Rails

API開発とRSpecコーディングに触れる機会は多かったです。bundleもトラブルが多かったので、そこそこ多く調べましたね…特にVagrantではnfsストレージ上でbundleがうまく動かないトラブルもありました。CコンパイルMacローカルのコアを認識しつつVagrantCentOSで動くみたいな(^_^;) kaminariがCで書かれているのも知って驚きました。

CSS

Animationやレイアウトについて、実作業ベースで苦しみました(笑) 特にレイアウトについては縦方向でのセンタリングの難しさや、ブラウザによって出る描画差異なども実践なくしてはわからないものが多かったです。 flexやjustify-contentなどの魔法の単語を知って作業がかなり楽になりました。translateとtop、bottomを組み合わせて縦位置をど真ん中に合わせるなども今は重宝しています。(これはいずれブログにまとめたい…)

WebRTC

ブラウザができることが大きく広がっていることを知りました。 以下のコード、htmlにて保存してChromeで開いてみてください。カメラが起動します(笑)

<html>
<body>
  <video id="video" width="640" />
</body>
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
<script>
  navigator.getUserMedia({ audio: true, video: { width: 1280, height: 720 } },
    (stream) => {
      const video = document.querySelector('#video');
      video.src = URL.createObjectURL(stream);
      video.onloadedmetadata = (e => video.play());
    },
    err => console.log("The following error occurred: " + err.name),
  );
</script>
</html>

ローカルHTMLでもカメラがいとも簡単に起動する、それを保存したりもできる、ネイティブアプリとブラウザとの違いはどんどん少なくなっているようです。

逆に言えば、Webエンジニアに求められることもどんどん増えているわけで、今後も精進が必要そうです(^_^;)

Xcode

業務都合で自社アプリのビルド程度まではおこなうようになりました。開発はまだ触れていませんが、エラーコンソールとBuild Settingくらいは読むようにはなっていました。ビルドを行うようになって意識が変わったことのひとつに、MacOSXcodeのバージョンは比較的早く最新のものを追うようになりました。

モヒカンSlack

kotakanbeさんが運用されているSlackチームですが、こちらの利用で情報収集の効率が格段に良くなりました。 qiita.com

冬眠気味だったTwitterアカウントも改めて情報収集に活かせるようフォローを増やしたり手をかけましたが、情報収集方法も年々進化していますね。

TILをやってみたが…

syossan.hateblo.jp

Today I learndでTILですね。1週間も持ちませんでしたが(^_^;)

ブログよりも細かい粒度で身につけたことを残したいと思いはじめましたが、情報が少なすぎると一生懸命ネタを増やそうとしてしまうのがブログやってるときの癖で… 調べたことを一個単位で残していくのは非常に効率的だと思うので、今後はもう少しマメに書いていきたいです!

GitHub - ttaniguchi/til: Today I learned

まとめ

今年はわたしにとってはクライアント元年であり、非常に楽しい試みを多く経験できた年だったと思います。ただ、環境的には同じ技術軸で作業をする人間が身近におらず、ガラパゴス懸念を感じながらLintだ勉強会だと他者の技術や標準化にやや枯渇した時期でした。 来年は身近なメンバーに技術普及をすることで切磋琢磨できる環境をつくることにも尽力したいですね。

それと、やはりネイティブには触れていきたいです。Reactjsかvuejsか、みたいな時期もありました。それでもReactjsを選んだのは「アプリも作れるみたいだし…」というとろこもあったわけで。 そこに回帰して、来年はプライベートでReact Nativeをはじめてみようかと思っています。(1年くらい前にHwllo Worldくらいまではやった気がします)

今年も残すところ僅かですが、良いお年を! Happy Hacking