Upgrade to Pro — share decks privately, control downloads, hide ads and more …

フロントエンドで 良いコードを書くために

てけし
January 18, 2023

フロントエンドで 良いコードを書くために

フロントエンドLT新年会の資料
https://thecoo.connpass.com/event/269188/

てけし

January 18, 2023
Tweet

More Decks by てけし

Other Decks in Programming

Transcript

  1. 写真が入ります 井上丈士 Sansan株式会社 技術本部 Strategic Products Engineering Unit Contract One

    Devグループ zenn: t-keshi twitter: t__keshi 趣味: サウナ駆動技術記事投稿
  2. 例えば責務を意識したレイヤー分け ❌悪い例 データ取得の責務 getUsers()などに切り出すべき 表示の責務 その背後にある考え方? const UsersPage = ()

    => { const [user, setUsers] = useState(null) useEffect(() => { const asyncFn = async () => { const response = axios.get("https://hoge-api/users", { headers: {...省略...} }) return response.data } asyncFn() }, []) return <UsersTable users={users} /> }
  3. 静的に分岐漏れを検出する。 条件分岐のコツ1 TypeScript 4.9以降 type Action = | { type:

    "OPEN"; payload: { message: string } } | { type: "CLOSE" } | { type: "TOGGLE" } const reducer = (action: Action) => { switch (action.type) { case "OPEN": return { isOpen: true, message: action.payload.message } case "CLOSE": return { isOpen: false, message: null } default: // TOGGLEがないのでコンパイルエラー throw new Error(action satisfies never) } } TypeScript 4.9以前 type Action = | { type: "OPEN"; payload: { message: string } } | { type: "CLOSE" } | { type: "TOGGLE" } const reducer = (action: Action) => { switch (action.type) { case "OPEN": return { isOpen: true, message: action.payload.message } case "CLOSE": return { isOpen: false, message: null } default: // TOGGLEがないのでコンパイルエラー throw new Error((action as { type: "__invalid__" }).type) } }
  4. 処理の分岐というより、単純な対応を表す場合は、 Switchの代わりにObjectを使う。 条件分岐のコツ2 type Status = "active" | "inactive" |

    "sleep" const UserStatus = (status: Status) => { const icon = { active: <ActiveIcon />, inactive: <InactiveIcon />, sleep: <SleepIcon /> }[status] return <div>{icon}</div> }
  5. RoRoとは、”Receive an Object, Return an Object” オブジェクトで受けてオブジェクトで返すこと RoRo const createUser

    = (userId: string, userAccountId: string) => { // 省略 } const UserRegistrationDialog = () => { const handleSubmit = (userAccountId: string, userId: string) => {   // 引数を渡し間違える   createUser(userAccountId, userId) } return <Dialog onSubmit={handleSubmit}/> } Objectを使うと混乱は防げる (他の言語でいう名前付き引数やキーワード引数) const handleSubmit = ({userId, userAccountId}) => { createUser({ userId, userAccountId}) }
  6. Gap

  7. 無闇にStateに入れまくる。 状態管理はシンプルに保つのがキモ。 ❌悪い例 例えばReactだと3 const HogeComponent = () => {

    const [users, setUsers] = useState() const [admin, setAdmin] = useState() // その他数多くのStateなど, 500行くらい return <div /> // ようやくJSX }