タブってイマイチだよね、という話
何らかの情報を表示する画面でありがちなのですが。
例えば、「詳細」と「編集」を url で切り替えず、タブで切り替える、みたいな要件って結構多いです。
もしくは、url のパラメータで切り替える、みたいなこともたまーにあります。
が、実はこれってフロント的には結構苦しかったりします。
以下、簡単に詳細をば。
今回は React っぽく書いていこうと思います。
まず、詳細画面を作ります。
const Hoge: FC = () => (
<ul>
<li>年齢:24際</li>
<li>職業:学生</li>
</ul>
);
これにタブをひっつけます。
const Hoge: FC = () => (
<div>
<div>
<div>詳細</div>
</div>
<div>
<ul>
<li>年齢:24際</li>
<li>職業:学生</li>
</ul>
</div>
</div>
);
編集タブとフォームもひっつけます。
const Hoge: FC = () => {
const [currentTab, setCurrentTab] = useState<"detail" | "edit">("detail");
const handleClick = useCallback<NonNullable<JSX.IntrinsicElements['div']['onClick']>({
currentTarget: {
dataset: {tab},
},
}) => {
if (tab !== 'exhibiting' && tab !== 'stock') {
return;
}
setCurrentTab(tab);
}, [setCurrentTab]);
return (
<div>
<div>
<div data-tab="detail" onClick={handleClick}>
詳細
</div>
<div data-tab="edit" onClick={handleClick}>
編集
</div>
</div>
<div>
{
currentTab === "detail ? (
<ul>
<li>
年齢:24際
</li>
<li>
職業:学生
</li>
</ul>
) : (
<form>
<ul>
<li>
年齢:<input />
</li>
<li>
職業:<input />
</li>
</ul>
<button type="submit">
送信する
</button>
</form>
)
}
</div>
</div>
)
}
ここにさらに submit の実装と、詳細と編集で共通の get を叩く処理が乗ります、もう書きませんが。
もちろん上記の例では container components と presentational components を分けていないので、実際にはもう少しスッキリします。
が、そもそもフォームの実装って container components がごちゃつくものなんですね。
編集画面ってどうしても処理が複雑になりがちなので、なるべく余計なことをやりたくないという気持ちがあります。
にも関わらず、詳細画面も兼ねたタブの実装を行ってしまうと、初期値や更新後の値の取得やタブの切り替えの実装も乗ってくるため、すげーぐちゃっとした実装になります。
また、出し分けの部分におけるパフォーマンスも気になりますし、入力途中にタブを切り替えられたりした場合の考慮なんかも場合によっては必要になってくるかもしれません。
加えて、テストを組むのもすげー複雑になりますし、ぶっちゃけあまり賢い UI/UX ではないと思います。
フロント的には、編集画面で編集が完了し、submit に成功したら、詳細画面に自動的に遷移する、くらいが無難なフローじゃないかなーと思います。
シンプルなデザイニングが必然的にシンプルな実装につながるため、タブにフォームを乗っけるような実装は控えるべきではないかなーと。
また、そもそもタブって実装を複雑にしがちなため、フォームの有無に限らず、最低限の使用に留めるべきだとも思っています。
タブを組むくらいなら画面を増やせばええやん、という認識ですね。
1 画面に表示する情報を最低限にすることが、スムーズなプロジェクト進行につながると思います。