LoginSignup
1
0

More than 1 year has passed since last update.

【React + TypeScript】Switch文を使って、動的に色を変える

Last updated at Posted at 2021-09-24

はじめに

この度、「RailsAPIのレスポンスの内容によって、画面の色を変化させる」という実装を行いました。その結果を、アウトプットとしてまとめました。

記事の内容

  • React + TypeScriptで色を動的に変化させることができるようになる

準備

  • 今回は、ChakraUIを使用しました。
npm i @chakra-ui/react @emotion/react@^11 @emotion/styled@^11 framer-motion@^4

Getting Started

今回使用するサンプルプログラム

App.js
import { ChakraProvider, Text, Center, Button, Box } from "@chakra-ui/react";
import React, { useState } from "react";

type FoodType = {
  name: string;
  value: number;
};

export default function App() {
  //オブジェクトの型定義が曖昧です。
  const [food, setFood] = useState<FoodType>({ name: "初期値", value: 0 });

  const foods = [
    { name: "りんご", value: 300 },
    { name: "ぶどう", value: 1000 },
    { name: "バナナ", value: 200 }
  ];

  const onClickButton = () => {
    const newFood = foods[Math.floor(Math.random() * foods.length)];
    setFood(newFood);
  }

  return (
    <>
      <ChakraProvider>
        <Box bg="black" m={4}>
          <Center>
            <Text color="white" fontSize="2xl" w="2xl" textAlign="center">
              名前: {food.name}
            </Text>
            <Text color="white" fontSize="2xl" w="2xl" textAlign="center">
              価格: {food.value}</Text>
          </Center>
        </Box>
        <Center>
          <Button onClick={onClickButton}>ボタン</Button>
        </Center>
      </ChakraProvider>
    </>
  );
}

ボタンをクリックすると、ランダムに取得したfoodに更新されるプログラムを作成しました。

スクリーンショット 2021-09-24 16 58 13

この状態から、foodsのnameによって、背景色が変化するプログラムを追加します。

実装

1.色を取得する関数を作成
ここで、タイトルにある通り、switch文の条件によって、色を取得しています。
例えば、food.nameが"りんご"の場合、red.400が背景色になります。

App.js
const getFoodColor = useCallback(
    (food: FoodType) => {
      switch (food.name) {
        case "りんご":
          return "red.400";
        case "ぶどう":
          return "blue.400";
        case "みかん":
          return "orange.400";
        case "バナナ":
          return "yellow.300";
        default:
          return "black.400";
      }
    },
    []
  );

2.色を取得し、変数に格納

先程作成した関数(getFoodColor)から、foodの値が変わった場合に、色を取得します。
また、メモ化して無駄な再レンダリングを制限しています。(foodの値が変更された場合のみ更新される)

App.js
const foodColor = useMemo(() => getFoodColor(food), [food])

3.取得した色を背景に設定
最後に、取得した色を背景として設定します。

App.js
//before
<Box bg="black" m={4}>

//after
<Box bg={foodColor} m={4}>
  • 全体像
App.js
import { ChakraProvider, Text, Center, Button, Box } from "@chakra-ui/react";
import React, { useCallback, useMemo, useState } from "react";

type FoodType = {
  name: string;
  value: number;
};

export default function App() {
  const [food, setFood] = useState<FoodType>({ name: "初期値", value: 0 });

  const foods = [
    { name: "りんご", value: 300 },
    { name: "ぶどう", value: 1000 },
    { name: "バナナ", value: 200 }
  ];

  const getFoodColor = useCallback((food: FoodType) => {
    switch (food.name) {
      case "りんご":
        return "red.400";
      case "ぶどう":
        return "blue.400";
      case "みかん":
        return "orange.400";
      case "バナナ":
        return "yellow.300";
      default:
        return "black.400";
    }
  }, []);

  const foodColor = useMemo(() => getFoodColor(food), [food]);

  const onClickButton = () => {
    const newFood = foods[Math.floor(Math.random() * foods.length)];
    setFood(newFood);
  };

  return (
    <>
      <ChakraProvider>
        <Box bg={foodColor} m={4}>
          <Center>
            <Text color="white" fontSize="2xl" w="2xl" textAlign="center">
              名前: {food.name}
            </Text>
            <Text color="white" fontSize="2xl" w="2xl" textAlign="center">
              価格: {food.value}</Text>
          </Center>
        </Box>
        <Center>
          <Button onClick={onClickButton}>ボタン</Button>
        </Center>
      </ChakraProvider>
    </>
  );
}
  • ボタンをクリックすると、色がランダムに取得でき、出力されるプログラムが完成しました。

りんご

ぶどう

バナナ

カスタムフック化

  • カスタムフック化をしておきます。
App.js
import { ChakraProvider, Text, Center, Button, Box } from "@chakra-ui/react";
import React, { useMemo, useState } from "react";

import { useFoodColor } from "./useFoodColor";
import { FoodType } from "../type/food";

export default function App() {
  const [food, setFood] = useState<FoodType>({ name: "初期値", value: 0 });

  const foods = [
    { name: "りんご", value: 300 },
    { name: "ぶどう", value: 1000 },
    { name: "バナナ", value: 200 }
  ];

  const { getFoodColor } = useFoodColor();
  const foodColor = useMemo(() => getFoodColor(food), [food]);

  const onClickButton = () => {
    const newFood = foods[Math.floor(Math.random() * foods.length)];
    setFood(newFood);
  };

  return (
    <>
      <ChakraProvider>
        <Box bg={foodColor} m={4}>
          <Center>
            <Text color="white" fontSize="2xl" w="2xl" textAlign="center">
              名前: {food.name}
            </Text>
            <Text color="white" fontSize="2xl" w="2xl" textAlign="center">
              価格: {food.value}</Text>
          </Center>
        </Box>
        <Center>
          <Button onClick={onClickButton}>ボタン</Button>
        </Center>
      </ChakraProvider>
    </>
  );
}
useFoodColor.ts
import { useCallback } from "react";
import { FoodType } from "../type/food";

export const useFoodColor = () => {

  const getFoodColor = useCallback((food: FoodType) => {
    switch (food.name) {
      case "りんご":
        return "red.400";
      case "ぶどう":
        return "blue.400";
      case "みかん":
        return "orange.400";
      case "バナナ":
        return "yellow.300";
      default:
        return "black.400";
    }
  }, []);

  return { getFoodColor };
};

型定義も別で切り出しました。

src/type/food.ts
export type FoodType = {
  name: string;
  value: number;
};

以上になります。

参考資料

JavaScript | 配列・多次元配列からランダムに値を取得する方法 | ONE NOTES

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0