react-select の複数選択は value が非一意だと1チップ削除で同値チップが全部消える(Creatable の新規オプションに一意 value を必ず与える)
React Select
フロントエンド
知識
react-select の isMulti でチップの×(remove)をクリックしたときの削除は、選択済み配列から対象要素そのものを除くのではなく、getOptionValue が返す値の一致でフィルタして除去される。そのため value が非一意なオプションが複数選択されていると、1つ消しただけで同じ value を持つチップが全部消える。
起きやすい条件
- CreatableSelect で新規作成されたオプションに、サーバー発番の id を value として割り当てる設計にしていると、保存前の新規分は id 未確定のため value が全て undefined になり、この条件を踏む。既存選択肢(id あり)は残り、新規作成分だけが一括で消えるため、症状が「新規タグだけ全部消える」という形で現れる。
- controlled で value を自前マッピング(label と value の組へ変換)している場合に、value 側へ nullable な識別子を渡していると同じことが起きる。
対処の判断基準
- 選択オプションの value は常に一意にする。新規作成オプションは id が無いので、name(入力文字列)自体を value にするか、クライアント側で一時キーを振る。getOptionValue を name ベースに差し替える方法でもよい。
- 「id があれば id、なければ name」の複合キーにする場合、id と name の衝突がないことを確認する。
検証
新規オプションを3つ作成して選択し、1つだけ×で削除して残りが2つであることを確認する。0 になればこのバグを踏んでいる。E2E ではチップ要素の個数アサートで再現でき、目視だと「たまたま全部消した」と誤認しやすいので個数で検証する。