dackdive's blog

新米webエンジニアによる技術ブログ。JavaScript(React), Salesforce, Python など

「各社CREチームのサポート体制と独自の取り組みについて【はてな|freee|アンドパッド】」参加メモ

参加しました。

動画

ハッシュタグ#hatena_freee_andpad

以下メモです。

テクニカルサポートをプロダクトの強みにするMackerel CREの取り組み

f:id:dackdive:20220224210845p:plain

f:id:dackdive:20220224210905p:plain

  • サポートのフロー

f:id:dackdive:20220224211345p:plain

  • CRE内にテクニカルサポートとカスタマーサクセスがある
    • 今日はテクニカルサポートの話が中心
  • どう対応しているか
    • すでに情報があるもの:セルフサービス化
      • 独自のセルフサービススコアという指標で、お客様がどれぐらい自己解決できたかをモニタリング
      • FAQの検索語監視君
        • FAQで検索したけど検索結果が0件だったものを、検索回数が多い順に定期的に Slack に流す f:id:dackdive:20220224210950p:plain
    • 定形の回答がないもの
      • CREによる調査:環境の情報提供、ソースコード確認、アプリケーションログ
      • CREでもだめならエスカレーション。開発チームにもサポート担当がいる
      • 応用的な活用方法の提案
    • 課題
      • ヘルプとFAQのプラットフォームが異なるので相互にサジェストできない
      • セルフサービススコアは実際に自己解決した割合ではない
      • プロダクトへのフィードバックループの強化

freeeのCRE誕生から現在までの歩みとセルフサービスへの挑戦について

  • 問い合わせフロー
    • ユーザー起点なのか開発者起点なのかでフロー分けてる。開発者起点の場合は最初からCREが対応

f:id:dackdive:20220224213156p:plain

  • プロダクトとチーム進化の軌跡
    • 最初はテクサポチーム
  • 業務内容 f:id:dackdive:20220224213315p:plain
    1. 問い合わせ対応
      • 全体のフロー改善も担当
      • 対象プロダクトはfreeeのプロダクトラインナップのうちの一部
    2. セルフサービス開発
      • chat bot開発など、ユーザーが自己解決できるしくみを
  • チーム構成
    • プロダクトごとにさらにユニットに分かれている
    • ユニットごとにOKRにを設定
      • ユーザー様回答までのSLOを持ってるユニットや、一次回答までのリードタイムを目標にしたり
  • チームの歩み
    • QAチームの1チームとしてテクサポ誕生
    • 最初はフローを整えることに専念

f:id:dackdive:20220224213723p:plain

  • エンジニアへの問い合わせ数は順調に減っている
  • 03 セルフサービスの開発
    • chat bot
    • お問い合わせフォーム統合
    • ヘルプページ刷新: Zendesk → React + TypeScript、検索を Algolia に
  • これから
    • ユーザー対応領域:解決時間を短く
      • セールスエンジニア的な動きを模索中
    • プロダクト対応領域:問い合わせを減らす

アンドパッドのテクニカルサポートと要件定義への関わり方

  • 問い合わせフロー
    • カスタマーサポート、営業、カスタマーサクセスが問い合わせを受ける
    • CREは問い合わせの一次窓口という感じ

f:id:dackdive:20220224213605p:plain

  • バグ対応フロー
    • CRE自身は修正まではやらない
  • テクニカルサポートにおける意識
    • SaaSであることを意識する
    • お客様の疑問の意味を常に考える
  • 現状の課題
    • 仕様か不具合かの判断が難しい
      • 仕様FAQ作成中
    • ドメイン知識の難しさ
      • オンボーディング資料として各種ドメイン資料を作成中
  • 要件定義への関わり方
    • 開発チーム側へCREとしての懸念を伝える
      • 関連する機能(影響範囲)
        • 機能が複雑化、マイクロサービス化により機能間の連携が増える
        • 問い合わせを一本化しているので様々な問い合わせが CRE に来る→幅広い知識を身につけているCREからの目線を伝える
      • 改善を実施することによって実現される運用上の影響
        • ある改善が一部のお客様にとってデメリットとなる

パネルディスカッション〜各社の取り組みのここが気になる!〜

Q. ドメイン知識はCREとしてどれくらい求められる?
  • 段階があると思う by アンドパッド
    • テクニカルサポートをするに十分なドメイン知識は教えていきたいと思っている。それを学ぶ方法がないというのが現状の課題
  • 専門的な知識が必要だと思うところはある by freee
    • プロダクトの仕様に関することは過去の問い合わせのナレッジなどもあるのでそれを参考にしながら
Q. CREはまだできて浅い職種なので、役割定義が難しいと感じています。どのようにCREを定義していますか?
  • はてな
    • セールスエンジニア→CREという経緯
    • 隔週ぐらいでCREについて考える会をやっていた
  • freee
    • 混乱期って書いてた
    • テクニカルサポートの延長戦上、って思われてしまいがちだけど、エンジニアとして問い合わせ自体をなくしていく活動も大事
  • アンドパッド
    • freee さんと似てるなと思った。2年遅れぐらいで歩んでる
    • エンジニアの負荷を下げて、エンジニアが本来やるべきことに専念できるようにする
Q. 各社CREの採用のときにどのようなCRE像をイメージしていますか?
  • freee
    • ドメイン知識は最初から要求していない
    • どちらかというとエンジニアの素養
    • 最先端の技術使いたい、よりユーザーに寄り添いたい、という気質の人
  • はてな
    • お客様の課題にどれだけ自分ごととして関心を持てるか
    • 面接でも「こういうこと言ってるお客様がいたらどのへん気になりますか?」とか聞く
  • アンドパッド
    • 顧客信頼性とはお客様の本当の課題を解決すること
Q. はてなへの質問
  • お知らせメールをCREで出すに至った理由は? by freee
    • セールスエンジニアからスタートしていろんな業務を吸収してったという歴史的経緯から
    • エンジニアは仕様とか厳密な文章書くのは得意だが、お客様が知りたいことを想像して書くみたいなのはCREの方が得意
    • お知らせ書くことがCREにとってめちゃめちゃ勉強になる、というのもある
Q. freee への質問
  • なにから手を付けるか、どこからやるか、という優先度はどう決めている? by はてな
    • CREだけで決めてるわけではなく、サポートチームと連携してやっている
  • チャットでも優先度の基準ってどういう感じで策定してますかってあった
    • あれは「サポートからエンジニアに依頼するときの優先度」の話だと思う
    • 優先度を策定した。代替手段がないもの、とか判断の軸を作った
Q. アンドパッドへの質問
  • 要件定義にも関わるとのことだが、そのきっかけは?
    • 元々は個人の経験を活かして。テクサポチームがない時代に、自分の役割とか抜きに誰かが困ってることをやっていた

所感

サポート体制や業務内容、現状の課題など各社の具体的な話が聞けて参考になりました。
CRE という職が生まれた歴史的経緯が会社によって様々なので、サポートひとつとってもどのような体制でCREが何をどこまで担うかはけっこう違う印象を受けました。また、どこも「CREとはこうあるべき」という絶対的な解は持ってなく模索中なんだなとも。

CRE は「エンジニア」である以上、日々のサポート業務にとどまらず技術で問題を解決することが求められると思っていますが、一方でフローの整備など泥臭く地道な作業も各社やられていて、そのへんは今まさに自分もやっていることなので安心しました。

TypeScriptの公式チートシートを読んだ

先週の This Week In React に流れてきたやつ。

ざっと読んでみたけどそこまで目新しい発見はありませんでした。以下メモ。 💬 はコメント。

Classes

f:id:dackdive:20220124011610p:plain
https://www.typescriptlang.org/static/TypeScript%20Classes-83cc6f8e42ba2002d5e2c04221fa78f9.png

class Location {
  constructor(public x: number, public y: number) {}
}

const loc = new Location(20, 40);
loc.x // 20
loc.y // 40
  • Abstract Classes
  • Decorators and Attributes
    • デコレータをクラス、メソッド、アクセサ、プロパティやパラメータに使えるよ、とだけ
    • どういう動作になるのかは書かれておらず

Interfaces

f:id:dackdive:20220124011739p:plain
https://www.typescriptlang.org/static/TypeScript%20Interfaces-34f1ad12132fb463bd1dfe5b85c5b2e6.png

  • Common Syntax
    • 💬 new XXX() したときの型の宣言とかしばらく知らなかった
      • new(s: string): JSONResponse;
  • Extension via merging
    • interface は複数宣言することでマージできる

Types

f:id:dackdive:20220124011836p:plain
https://www.typescriptlang.org/static/TypeScript%20Types-4cbf7b9d45dc0ec8d18c6c7a0c516114.png

左上の Type vs Interface にどっち使う?の判断材料について言及されていた。

  • Type vs Interface
    • Interface はオブジェクトの形状を表現するのにしか使えない
    • Interface は複数回宣言することで拡張できる
    • パフォーマンスがクリティカルな型は Interface のほうが速い可能性がある
  • 💬 このへんの型については新しい知見はなかった
    • Primitive Type, Object Literal Type, Tuple Type, Union Type, Intersection Types(& によるマージ)
  • Type Indexing
  • Type from Value: typeof 値 で値を元にした型が作れる
  • Type from Func Return: ReturnType<関数の型> で関数の戻り値の型が作れる
  • Type from Module

以下はライブラリを作成するときや既存のJavaScriptコードを表現するときに素晴らしい機能だが、多くのTypeScriptアプリケーションではほとんど使わないとのこと。

  • Mapped Types
type Artist = { name: string, bio: string };

type Subscriber<Type> = {
  [Property in keyof Type]:
    (newValue: Type[Property]) => void
}
type ArtistSub = Subscriber<Artist>
  • Conditional Types: A extends B ? C : D
  • Template Union Types
    • 型にテンプレートリテラルを使う
    • type AllLocaleIDs = `${SupportedLangs}_${FooterLocaleIDs}_id`

Control Flow Analysis

f:id:dackdive:20220124011918p:plain
https://www.typescriptlang.org/static/TypeScript%20Control%20Flow%20Analysis-8a549253ad8470850b77c4c5c351d457.png

  • If Statements
    • if で型を絞り込む
  • Discriminated Unions
    • Union の各メンバが同じプロパティを持っている場合、 if や switch で型を絞り込める
type Responses =
  | { status: 200, data: any }
  | { status: 301, to: string }
  | { status: 400, error: Error }
  • Type Guards
    • 関数の戻り値の型に is を使うやつ
    • これは as と同じく TypeScript の推論に頼らず自分で宣言しているだけなので取り扱い注意
  • Assertion Functions
    • 関数の戻り値の型を asserts <引数> is SomeType で定義するやつ
  • Assignment
    • as const

所感

  • 「全然知らねえ!」というのはなかったよかった
  • Mapped Types とか Conditional Types とか Assertion Functions とか、説明聞いただけだとよくわからんみたいなのが最低限のサンプルコード載せてくれてるのはありがたい

KPT以外のふりかえり手法について調べた

背景

現職のログラスでは週に3回ぐらいのペースで10分勉強会というものをやっています。

先日そこでふりかえり手法について話したので、自分のブログにも残しておきます。
社内事情的なものを消した以外は、ほぼ勉強会のときに使った資料そのままです。

---------------資料ここから------------------

少し前に見たこの資料が面白かったので、+αで調べたことも含め紹介します

本日のゴール

  • KPT以外にもこんなふりかえりあるんだ〜というのを知ってもらう
  • それぞれのチームでいろんなふりかえり試してみようという機運になる

はじめに

実は奥が深いふりかえり
  • ふりかえりだけで1冊の本になる

f:id:dackdive:20220113015304p:plain:w240f:id:dackdive:20220113015308p:plain:w240

個人的にはKPTもけっこう難しい面があると思っている

KPT以外の方法も選択肢として知っておくといいよね!ということで調べた


ふりかえり手法の紹介

主に冒頭のスライドと、ふりかえりカタログ を参考に。

1. タイムライン

f:id:dackdive:20220113015749p:plain

  • チームでもちょっと取り入れてる
  • 事実ベースで書き出すので良いこと悪いこと思い出すきっかけになるのは👍
  • 毎日書かないと1週間でも思い出せないという学び
2. Fun / Done / Learn

f:id:dackdive:20220113015832p:plain

  • 前職で一時期やってた
  • 進め方に書いてないけど、最初に今週やったことを事実ベースで書き出してから図にマッピングする
    • →タイムラインと同じく、事実ベースで思い出すので感情に左右されにくい
  • KPT よりポジティブな雰囲気になりやすい
    • チーム作りたてのときとかメンバーにシャイな人が多いと効果アリ
  • (良い意味で)今のログラスでは別に必要ないかなーという印象
    • Kも出てるし、Pもそんな暗い雰囲気にならず議論できてるので
3. Good & New

f:id:dackdive:20220113015940p:plain - 前職ではデイリーチェックイン時のざつだんで使ってた - これ単体で使うというよりはふりかえりとかのアイスブレイク的用途かな

4. 象、死んだ魚、嘔吐

f:id:dackdive:20220113020156p:plain

  • ネーミングセンスよ
  • やったことはないが、各項目を読むと意外と理にかなってるのでは?という気も
  • 月1とか、ちょっとまとまった期間におけるふりかえりとかによさそう
5. Six Thinking Hats (6つの帽子思考法)

f:id:dackdive:20220113020017p:plain

  • モブプロの本に出てきた
  • 類似のものとして「斜に構える、構えないを繰り返す」というのがある
    • こっちのがシンプル
  • どちらも、強制的に批判的・ネガティブな意見を出させるのは言いにくいこと言わせるという点でよさそう

おわりに

  • なんでこんな話をしようと思ったかというと、「気軽に実験できる文化を維持したいよね」みたいな気持ちがあった。自戒もこめて
  • 前提として、何かをするときに「なんでやるのか」「どんな効果を期待しているのか」を考えておくの大事
  • 一方で、やってみないとわからないこともある
  • 「それなんでやるんですか」をやりすぎると何も実験できない組織になる
  • ふりかえりのやり方にしてもそうで、実験のハードルとしてはめちゃ低い
    • 失敗してもたかが1週間なのでどんどん実験してみよう。自戒もこめて
  • アトラクタの永瀬さんもこんなことを言っている

先が読めないからこそアジャイルが役に立つ 予定調和にハマらないためのスクラム活用術

実際にControlled Chaos……制御されたカオスという言い方をしたりします。その中で安全に実験や失敗をしてみることが、そもそものアジャイルスクラムの価値かなと私は考えていて。
...
アクションに起こしやすくて、計測可能なトライというか改善を上げることはもちろんいいんですが。そうではなくて、お願いしたいことはたまに実験をしてみてほしい。一見何も相関がなさそうなことをやってみると、実はあとから因果があったと判明するかもしれません。

  • 制御されたカオスを楽しもう!

参考リンク

------------資料ここまで---------------

後日談

この話をした翌日が月次振り返りで、早速「象、死んだ魚、嘔吐」を試してみようという動きになった。それだけでも話してよかった。

2021年のふりかえりと2022年にやりたいこと

完全に年を越してしまったが、毎年書いてるので書く。

去年:

dackdive.hateblo.jp

2021年の四半期ごとのふりかえり:

読んだもの

第一特集の「[自作OS×自作ブラウザで学ぶ]Webページが表示されるまで」が気になって買った。
けっこうシステムコールのところとか難しくて理解があやふやだった記憶。

これは WebAssembly 特集が読みたくて。
読書メモ:Software Design 2021年3月号の「WebAssembly入門」を読んだ - dackdive's blog

今だと 日本語訳 も出ているのでそっち買った方がいい。

読書メモ:「The Art of WebAssembly」を読んだ - dackdive's blog

一瞬だけ Ansible をやる必要性にかられて買った。
前半しか読んでないが、Playbook とか Inventory といった基本的な用語が公式ドキュメント読むよりはるかにわかりやすく説明されててよかった。

面白かった。こういう本もっと読みたい。
得意なこととはなにかっていうエピソードが印象的だった。

仕事をするとき、同じくらいのエネルギーを注いでいるはずなのに、妙によろこんでもらえるときと、あんまりよろこんでもらえないときがあるんですよ。
(中略)
つまり、自分たちがすごく苦労したと思ってないのに、妙に評価してもらえるときというのは、放っておいても、どんどんいい結果が出て、いい循環になって、どんどん力が出ていく状態。それが自分たちに向いている得意なこと、そうじゃないことは向いてないことだ、というふうに、わたしはだいたい判断していますね。

これも面白い本だった。仕事と全然関係ない息抜きに良かった。

評判良さそうだったのと Concurrent Mode あたり気になって読んだ。だいたい全部読み終わったはずだけど読書メモ書けてないな...

書いたもの

時系列で。だいたいこのブログで、たまに Zenn の方にちゃんとまとめた情報を書くようにしてた。

作ったもの

これぐらい。

Pixe.la という草生やす API サービスをブラウザ上で試せる君。

あとは、2020年の終わりぐらいから読んだ記事はここに残すようにした。
https://reading-list.zaki-yama.dev/

所感

ざっくり、1年の前半は Rust や WebAssembly を勉強していて、後半は追いつけてなかったフロントエンド技術のキャッチアップに注力していた。
後悔はないが、最近は Rust は全く勉強できてなくて、周りでやってる声もよく聞くようになったのでもっかい一から入門したいなという気持ち。

今年の後半には University of the People (UoPeople) への入学と株式会社ログラス への転職という比較的大きな決断が2つあった。
UoPeople に関しては無事最初の term を乗り越えてもうすぐ 2 term 目も終わろうかというところ。正直まだ面白いと思える授業内容ではない (その前段の基本的なプログラミングの授業をやっている) が、このペースなら仕事や子育てと並行して続けられそうだという感触が得られたのは良かった。のんびりやっていきたい。
転職に関しても良い選択だったと思っている。以前の職場もそうだが、優秀で人間的にも良い人たちに囲まれているのはとてもありがたいこと。もうすぐ3ヶ月経とうとしているので転職エントリを書きたい。

2022年にやりたいこと

去年も書いた気がするけど、大きく変えたい・新たに挑戦したいみたいなことはなくて、引き続きコンピューターサイエンスや Web フロントエンドの勉強を継続していきたい。

コンピューターサイエンスはよくも悪くも UoPeople 以外のことを始める余裕はないので挫折しないよう頑張る。
去年以上に頑張る必要があると思ったのはフロントエンド領域で、Hooks 時代の React における設計の知見だったりとかテストまわりだとかで自分がリードできるほどの能力がないと感じており、このあたりは喫緊の課題。当面はフロントエンドのテストのことを勉強したい。

あとは Rust。なんとか時間を見つけて勉強を再開したい。。。

おわりに

2021年は引き続きコロナでメンタル的に辛いときもあったので、なんもできなかったなーとか思ってたんだけど、こうしてふりかえると一応前の年よりは前進してる感じがして良い。

2022年もよろしくお願いします。

2021年7月〜9月のふりかえり

前回:2021年4〜6月のふりかえり - dackdive's blog

✨ やったこと

7月: The Art of WebAssembly を読んだ

6 月から読み始めて、感想ブログを書いたのが 8/2。約2ヶ月かかった。

感想

dackdive.hateblo.jp

8月: Next.js, SWR, Chakra UI などを勉強した

8月は読書を一旦やめて、最近あまりキャッチアップできてないと感じていたフロントエンド周りの技術を勉強した。
結果としてこのようなものを作った。

9月: University of the People (UoPeople) に入学した

前四半期で申し込みまで済ませていた UoPeople だが、9月から本格的に講義がスタートした。
正確にはまだ正式な学生にはなれてなくて、Degree Student と呼ばれる正式な学生になるために必須の科目を受講している。

今は UNIV 1001 Online Education Strategies という一般教養みたいな科目と CS 1101 Programming Fundamentals (Python) というプログラミング基礎みたいな科目の2コマをやっている。すでに限界。

📝ブログ

↑に挙げたものがすべて。

💬 所感

気持ちの部分ではあんまり書くことがない。良い意味では前四半期より気持ちが前向きになっているということなのかもしれないし、悪い意味ではこの四半期大したことしてなくてほぼ記憶がないということなのかもしれない。

それでも、8月にキャッチアップしたかった技術を学べたし9月入ってからは大学の講義についていくので精一杯で、充実感はある。

💪次の四半期(2021年10〜12月)のテーマ

次の四半期でやりたいこと、というのがあんまり思いつかない。。。

  • まずは UoPeople で受講中の2コマちゃんと単位とって正式な学生になりたい
  • 本だと📕 Rust in Action かな

💸 買ったもの

本ぐらい。

Pixela APIをブラウザ上で試せるPlaygroundをNext.jsで作った

作った。
f:id:dackdive:20210905015031p:plain:w480

最低限の機能しかないしコードも汚いところいっぱいあるけどとりあえず公開することにした。
ここで試せます。

pixela-api-playground.zaki-yama.dev

ソースコードはこちらに。

モチベーション

ここのところ仕事では SDK など GUI を持たないライブラリやCLI を作ることが多く、Next.jsswr といった最近よく聞くフロントエンド技術スタックを素振りできずにいて危機感があった。

これらの素振りをするのにちょうどよい題材はないものかと思っていたところ、 Pixela という API サービスに出会ったので
この API をブラウザ上で実行できる簡単な Web アプリケーションを作ってみた。

Pixela について、詳しくは公式サイト(https://pixe.la/ja) の説明に譲るとして、GitHub の Contribution Graph のような草を生やすことができる API サービス。
習慣化したい活動を何でも記録して草を生やすことができる。最高。

自分の場合は、日々の読書時間を記録して GitHub ぽく見れたらなーと思っていたところこのサービスを見つけた。

Pixela は、 すべての機能が REST 風の API でしか提供されていない ところが特徴的。つまり、最初のユーザー登録から何からすべて curl などを利用して直接 API を叩いて行う必要がある。

これは API を利用することに慣れたプログラマにとって非常にとっつきやすい一方、特に最初どんな API があるのか、どんなリクエストに対してどんなレスポンスが返ってくるのかを色々試したいようなときには GUI でのインターフェースもあると自分以外の人にとっても便利かもなーと思い、ブラウザ上で API を一通り試せるようなサイトを作ることにした。

機能について

今のところは本当に各種 API を揃えただけ、という感じなので、便利機能とかはないです。
グラフ表示 API など一部の APIJSON ではなく SVG でレスポンスが返ってくるが、そういったものはサイト上で直接画像が見られるようになっている。

f:id:dackdive:20210905003457p:plain:w480

今後時間があれば作りたい機能はいくつかあって、

  • ログイン機能
    • 自分が使う上で一番ほしい。username, token を毎回入力したくない
  • レスポンスの JSON をコピーするボタン
  • ユーザーのグラフをまとめて表示するページ
    • どちらかというとダッシュボードでは感はあるが
  • サポーター限定の機能(パラメータ)はそれとわかるようにしたい
  • ダークモード対応
    • 技術的にやってみたいというだけ

などなど。

反応があればやる気も上がると思うので、リポジトリに Star をお願いします...🙏

技術的な話

今回使った主な技術スタックは以下。

それぞれ、初めて使ってみた感想とかよくわからなかったとこを書く。

Next.js

公式ドキュメントが非常に充実しているので、まずは Learn Next.js を一通りやってその後は必要になった機能だけ個別に調べる、というやり方で十分だった。

今回は必要にならなかったけど SSG、SSR、ISR の違いとかが理解できた。

SWR

今回のようにボタン押したらリクエスト送るだけのアプリに対しては完全に too much だったとは思うものの、どういう使い勝手なのか試したくて導入した。

条件付きフェッチ – SWR
の項にもあるように、「ボタンが押されたら useSWR() する」のではなく「レンダリングのたびに常に useSWR() は実行されるので、実際に fetch するかどうか別の state で管理する」というところは
ちょっとこれまでと発想を変える必要があった。けど hooks に共通して言える考え方なんだろうな、そういう意味で hooks 時代の設計に頭が追いついてないんだろうなとも思った。

あと、恥ずかしながらしばらく fetch や axios などのライブラリの代わりとして選択できるものだと思っていて、あくまでデータの「取得」用のライブラリだということに遅れて気がついた。
ref. how to use post method and pass params in swr? · Issue #93 · vercel/swr

🤔 わからなかったこと

クエリパラメータがそこそこあるような API を叩くとき、 useSWR()key パラメータをどう指定するのがお作法的に正しいのかよくわからなかった。

引数 – SWR にあるように第一引数の key には配列を渡せるが、

const { data: user } = useSWR(['/api/user', token], fetcher)

クエリパラメータが複数あるからといってそれをオブジェクトにまとめてしまうのは NG とされている。

// NG
const { data: events } = useSWR(['/api/events', { from, to }], fetcher)

基本的にクエリパラメータが異なると別々の結果としてキャッシュしたいから key には含めておきたいと思うんだけど、
クエリパラメータが増えるごとに配列に追加することになる?

そうすると fetcher 関数の引数も増えて...って思ったけど、第二引数をこう書けばいいのか。

const { data: events } = useSWR(['/api/events', from, to], (url, from, to) => fetcher(url, { from, to })

Chakra UI

よくある UI コンポーネントライブラリの1つとして必要なものだけ使った、という感じなので、どのあたりに強みがあるのかとかはまだ理解が不十分。

Comparison - Chakra UI
ここを一回ちゃんと読んだほうがいい。

あと、Chakra UI を使えば Tailwind CSS の思想とかも理解できるかと思ったけど全然そんなことはなかった。

あわせて読みたい

React Hook Foom

フォーム項目にきめ細かいバリデーションを実装したい場合に力を発揮しそうだなと思いつつ、今回は必須項目ぐらいしかなかったのでこれも too much ですね。

また、Chakra UI のドキュメントに
Chakra UI + React Hook Form - Chakra UI
なんてページもあるぐらいだから両方組み合わせるのも余裕なんだと思ってたけどそんなことなかったです。
ラジオボタン (Radio, RadioGroup) にどう組み込むのかわからず今のところこうなっている。

<FormControl>
  <FormLabel>type</FormLabel>
  <Controller
    control={control}
    name="type"
    render={({ field: { onChange, value } }) => {
      return (
        <RadioGroup onChange={onChange} value={value}>
          <Stack spacing={4} direction="row">
            <Radio value="int">int</Radio>
            <Radio value="float">float</Radio>
          </Stack>
        </RadioGroup>
      );
    }}
  />
</FormControl>

🤔 わからなかったこと

「単純なラベルつき input + 必須バリデーション + エラー時のメッセージ表示」みたいなことをやろうとすると
こういうコードを何回も書くことになる。

<FormControl isInvalid={!!errors.username}>
  <FormLabel htmlFor="username">username</FormLabel>
  <Input
    id="username"
    type="text"
    {...register("username", {
      required: "This is required.",
    })}
  />
  <FormErrorMessage>
    {errors.username && errors.username.message}
  </FormErrorMessage>
</FormControl>

さすがにこれはめんどいってことでコンポーネントに切り出したけど、TypeScript の型が合わず何箇所か挫折してる。

type Props<TFieldValues extends Record<string, any>> = {
  name: keyof TFieldValues;
  required?: boolean;
  register: UseFormRegister<TFieldValues>;
  errors: FieldErrors<TFieldValues>;
};

export default function Input<TFieldValues>({
  name,
  required,
  register,
  errors,
}: Props<TFieldValues>) {
  return (
    <FormControl isInvalid={!!errors[name]}>
      {/* @ts-ignore */}
      <FormLabel htmlFor={name}>{name}</FormLabel>
      <ChakraUIInput
        // @ts-ignore
        id={name}
        type="text"
        // @ts-ignore
        {...register(name, {
          required: required && "This is required.",
        })}
      />
      {/* @ts-ignore */}
      <FormErrorMessage>{errors[name]?.message}</FormErrorMessage>
    </FormControl>
  );
}

これは正解がよくわからない。