Closed8

"You and 120% Cleaner React"を見ながら過去のクソコードを成仏させる

ゆーせいゆーせい

最初は「冥冥たる濁流の useState」を浄化していきます

↓冥冥たる濁流の useStateの説明

これは、React フックスの useState を多用しすぎて、読みづらくなってしまうという問題です。
このアンチパターンの背景には様々な要因が存在しますが、はじめに挙げるのはシンプルに複数の useState をまとめるということを怠ったパターンです。

ゆーせいゆーせい

浄化すべき「冥冥たる濁流のuseState」はリポジトリから見つかりませんでした。
過去の自分やるやん

ゆーせいゆーせい

次は「2. 絶えず自壊するクソでかコンポーネント」です。
これは思い当たる節がありすぎる

ところで、巨大コンポーネントの真の問題は、単に大きいことだけではありません。
本当に厄介なところは、きちんと責務が切れていないところです。

グサッ

ゆーせいゆーせい

クソデカコンポーネント発見、、、
中略を挟みましたが、なんとこのファイルには100行を超えるコンポーネントが複数あります。


  return (
    <Box maxHeight="100vh">
      <HStack>
        <OrderButton handleAddToCart={handleAddToCart} />
        <Card w={'60vw'} h={'96vh'} p={4} m={2}>
          <h1>注文内容</h1>
          <Stack bgColor={'gray.50'} h={'88vh'} overflow={'scroll'}>
            {cart.map((order, index) =>
              order.name === 'ソース(セット)前売り' ? (
                <HStack key={order.id}>
                  <SetCard
                    order={order}
                    cart={cart}
                    handleUpdateOrderCheck={handleUpdateOrderCheck}
                  />

                  <Button
                    w="12vw"
                    h="20vh"
                    borderRadius={10}
                    m={5}
                    onClick={() => {
                      handleDeleteSetMenu(index);
                    }}
 ----------------------------------------中略------------------------------------------
          handleAddToCart({
            id: v4(),
            name: 'ソース(セット)前売り',
            price: 0,
            arranges: {
              kind: 'sauce',
              sauce: true,
              mayo: true,
              aosa: true,
              katsuo: true,
            },
          });
          handleAddToCart({
            id: v4(),
            name: 'めんたい(セット)前売り',
            price: 0,
            arranges: {
              kind: 'mentai',
              sauce: true,
              mentaiMayo: true,
              cheese: true,
              katsuo: true,
            },
          });
        }}
      >
        セット
      </Button>
    </VStack>
  );
};

export default ReceptionUI;

ゆーせいゆーせい

ではこのコンポーネントにどんな責務が混在しているか見ていきましょう。

このコンポーネントは露店の注文を受け付ける、受付画面です。そのため本来の責務は、受付機能を支える各コンポーネントを表示させることだと思います。
しかし、現状は

  • カートに入っている商品を配列の内容によって表示する
  • 合計金額を配列から計算して表示する

という本来負うべきでない責務も背負ってしまっています。

return (
    <Box maxHeight="100vh">
      <HStack>
        <OrderButton handleAddToCart={handleAddToCart} />
        <Card w={'60vw'} h={'96vh'} p={4} m={2}>
          <h1>注文内容</h1>
          <Stack bgColor={'gray.50'} h={'88vh'} overflow={'scroll'}>
            {cart.map((order, index) =>
              order.name === 'ソース(セット)前売り' ? (
                <HStack key={order.id}>
                  <SetCard
                    order={order}
                    cart={cart}
                    handleUpdateOrderCheck={handleUpdateOrderCheck}
                  />

                  <Button
                    w="12vw"
                    h="20vh"
                    borderRadius={10}
                    m={5}
                    onClick={() => {
                      handleDeleteSetMenu(index);
                    }}
                  >
                    削除
                  </Button>
                </HStack>
              ) : order.name === 'めんたい(セット)前売り' ? (
                <Box key={order.id}></Box>
              ) : (
                <HStack key={order.id}>
                  <Box width={'40vw'}>
                    <Grid
                      templateColumns="repeat(2, 1fr)"
                      gap={4}
                      marginLeft={5}
                    >
                      <GridItem
                        colSpan={1}
                        h="10vh"
                        w="4vw"
                        bg="blue.400"
                        borderRadius={10}
                        color={'white'}
                        p={'1.4vw'}
                      >
                        単品
                      </GridItem>
                      <GridItem colSpan={1}>
                        <Card key={order.id} w={'35vw'} minH={'8vh'} mt={2}>
                          <h2>{order.name}</h2>
                          <HStack>
                            <CheckboxGroup>
                              {Object.keys(order.arranges)
                                .slice(1)
                                .map((topping, i) => (
                                  <Checkbox
                                    key={i}
                                    defaultChecked={true}
                                    colorScheme="green"
                                    onChange={(e) => {
                                      handleUpdateOrderCheck({
                                        id: order.id,
                                        arrange: topping,
                                        checked: e.target.checked,
                                      });
                                    }}
                                  >
                                    {translateWords(topping)}
                                  </Checkbox>
                                ))}
                            </CheckboxGroup>
                          </HStack>
                        </Card>
                      </GridItem>
                    </Grid>
                  </Box>
                  <Button
                    w="12vw"
                    h="10vh"
                    m={5}
                    borderRadius={10}
                    onClick={() => {
                      handleDeleteFromCart(order.id);
                    }}
                  >
                    削除
                  </Button>
                </HStack>
              ),
            )}
          </Stack>
          <HStack>
            <h2>合計</h2>
            <h2>
              {
                //注文の合計金額を表示
                cart.reduce((sum, order) => sum + order.price, 0)
              }
            </h2>
            <PayDrawer />
          </HStack>
        </Card>
      </HStack>
    </Box>
  );
ゆーせいゆーせい

このコンポーネントの責務を各部品を表示するだけに修正しました。
なんと30行程度のコンポーネントに🤩
美しいですね

return (
    <Box maxHeight="100vh">
      <HStack>
        <OrderButton handleAddToCart={handleAddToCart} />
        <ShowCart
          cart={cart}
          handleDeleteFromCart={handleDeleteFromCart}
          handleUpdateOrderCheck={handleUpdateOrderCheck}
          handleDeleteSetMenu={handleDeleteSetMenu}
          translateWords={translateWords}
        />
      </HStack>
    </Box>
  );
このスクラップは2ヶ月前にクローズされました