つまずきニュースレター(2024-04-26号)
はじめに
こんにちは。ファンタラクティブの yoshino です。
ファンタラクティブのエンジニアチームはMob.*(モブアスタリスク)という取り組みを毎週行っており、それぞれのメンバーがどのような開発に取り組んでいるか・業務でつまづいたことを社内で共有しています。
このニュースレターでは、その中でも実際の業務で起きたつまづきをピックアップし、まとめています。
拡張機能で表示しているコンポーネントの state に応じて、表示しているページに新たに UI 要素を埋め込み表示する
原因
state 内容を storage に保持して、この保持値を見て UI 要素を出し分けるがオーソドックスな気がするが、以下の 2 つの理由から採用判断しませんでした。
- state の更新頻度が高い
- API 呼び出し状態が更新される度、埋め込み先ページに存在するフォームの各種入力欄の値が変更される度に state を更新する必要がある。
- state の容量が大きい
- 埋め込み先ページに存在する各種フォームの数が不定 かつ フォームの各種入力欄の値が大きい
対応
createPortal を利用して state 管理しているコンポーネント側で新しい UI 要素を表示ページ内の要素にぶら下げるようにしました。
これにより、親コンポーネントとは異なる部分の DOM に新しい UI 要素を直接組み込むことが可能になります。
こうすることで、state が頻繁に更新される問題や、HTMLElement を含む state の問題を回避し、より効率的かつ効果的に UI 要素をページに組み込むことができます。
Tanstack-Query v5 のコールバックをカスタムで実装する
原因
Tanstack Query v5 から onSuccess / onError が削除されました。
かなり大きな変更であることもあり、この発表をしたポストにも賛否両論が集まっています。
メンテナの方からは、どのような理由でその決断に至ったのかをまとめた記事が出されています。
その経緯の一部には
- staleTime が定義されている・さらにその時間内の場合、データフェッチをしてもキャッシュが返却されるため onSuccess が呼ばれない
- onError のコールバックは useQuery ごとに呼ばれるため、同じキーの useQuery を複数コンポーネントで使用するとそれぞれで onError が呼ばれる
といったような内容が記載されています。onSuccess / onError は直感的な API ですが、キャッシュなどが絡んできてその直感から外れた挙動をすると途端に開発者にストレスを与えそうな気もします。(その対応をするメンテナも大変そう)
確かに使い方によっては上記のようなバグを引き起こす可能性がありますが、使う側が責任を持ってその仕様を理解していれば onSuccess / onError のインターフェースはとてもわかりやすいものだと思います。
また、v4 から移行する際は破壊的すぎてスムーズな移行が難しい場合もあると思います。
ということで、試しに useQuery をラップして onSuccess / onError を追加した hooks を定義してみました。
対応
export type QueryCallbacks<TData, TError = DefaultError> = {
onSuccess?: (data: TData) => void;
onError?: (error: TError) => void;
onSettled?: (data?: TData, error?: TError) => void;
};
export const useQuery = <
TQueryFnData = unknown,
TError = DefaultError,
TData = TQueryFnData
>(
params: UseQueryOptions<TQueryFnData, TError, TData> &
QueryCallbacks<TData, TError>
): UseQueryResult<TData, TError> => {
const { onSuccess, onError, onSettled, ...queryParameters } = params;
const result = originalUseQuery<TQueryFnData, TError, TData>(queryParameters);
useEffect(() => {
if (result.isSuccess && onSuccess) {
onSuccess(result.data);
}
if (result.isError && onError) {
onError(result.error);
}
onSettled?.(result.data, result.error || undefined);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [result.isSuccess, result.isError, result.data, result.error]);
return result;
};
上記のようにラップした hooks を使用すれば、使用感的には今までと変わらずに使用できるかと思います。
参考
Postgres で JSON の中身を比較しようと思ったらうまく型が合わない
原因
postgres で配列の中身のデータを比較しようとしたら、型が合わずにうまく比較ができませんでした。
postgres には jsonb_array_elements という引数の jsonb 型の配列を展開してくれる関数があります。これを用いて配列の中身を展開し、各要素を比較しようとしたところ型がうまく合わずにエラーになってしまいました。
jsonb_array_elements(foo.names) AS foo_name
対応
以下のように展開した要素を Integer キャストすることで、問題なく比較することができました。
jsonb_array_elements(foo.names)::integer AS foo_name
各フィールドの型を確認したい場合は以下の記事のような方法で確かめることができます。
参考
AWS の請求が激増していた
原因
Amazon RDS で実行している MySQL 5.7 のデータベースインスタンスが、2024 年 2 月 29 日から Amazon RDS 延長サポートに自動登録されるようになっていたため、追加料金が発生していました。
延長サポートとはデータベースエンジンのサポートが公式に終了した後に、追加の料金を支払うことで延長サポートを利用することができるというサービスで、継続して安全に使用することを可能にするのですが、このサービスは自動的に適用されて予期せぬ追加費用が発生することにつながるので、課金の通知みたいな仕組みを入れて管理する必要がありそうです。
また、2024 年 2 月 1 日より、パブリック IPv4 アドレスの利用に対して新しい料金体系が導入されたため、追加料金が発生していました。
これは、IP アドレスの枯渇問題を背景に、リソースの有効活用を促進するための措置とされています。
対応
延長サポートについては、DB のアップグレードすれば延長サポートは必要ないとのことなので、DB アップグレードを行うことで対応しました。
IPv4 アドレスの料金変更については、IPv6 アドレスの使用に切り替えることで、この課金を避けることが可能ですが、現状のプロジェクトの状態を考慮して、引き続き IPv4 アドレスを使用することに決定しました。
参考
おまけ 🍪
Amazon RDS 延長サポートの件は同じようにつまずいている方がいるかもしれませんね。
一度請求のご確認を!
最後に
ファンタラクティブではフロントエンド・バックエンド問わず絶賛エンジニア募集中です!
気になる方は下のリンクをクリック!
ユーザーファーストなサービスを伴に考えながらつくる、デザインとエンジニアリングの会社です。エンジニア積極採用中です!hrmos.co/pages/funteractive/jobs
Discussion