14
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

~環境構築不要~ 絶対につまづかないReact入門

Last updated at Posted at 2021-09-28

前提条件

ワークショップにあたって必要な知識

  • JavaScript(ES6)の基本的な構文
  • HTML/CSSの基本的な構文

はじめに

本ワークショップのゴール

最終的な成果物

指定した色の補色と、その色の組み合わせを利用したUIのプレビューが見れるアプリケーション
image.png

使用ツール / ライブラリ

ツール/ライブラリ名  説明
CodeSandbox Web上で利用できるブラウザIDE(統合開発環境)
React フロントエンドライブラリ
Chakra UI Reactで利用できるUIコンポーネントライブラリ

補色のカラーコードを教えてくれるアプリを作ろう!

補色とは

混合して無彩色を作れる2色の有彩色の組み合わせを互いに補色(ほしょく、英: complementary color[1])であるという

補色同士の色の組み合わせは、互いの色を引き立て合う相乗効果があり、これは「補色調和」といわれる[3]

『フリー百科事典 ウィキペディア日本語版』

本セクションで実装するもの

  • 任意の色を入力する機能
    image.png

  • 補色を表示する機能
    image.png

Reactプロジェクトの作成

  1. CodeSandboxにアクセスする
  2. 「Create Sandbox」を押下する
    image.png
  3. 「React」を選択する
    image.png
  4. この画面が出たらOK
    image.png

テキストを書き換えてみる

  1. App.jsというファイルにある<h1>タグや<h2>タグで囲まれたテキストを好きな言葉に変更する
App.js
import "./styles.css";

export default function App() {
  return (
    <div className="App">
      {/* 「Hello CodeSandbox」を書き換える */}
      <h1>好きな言葉でいいよ!</h1>
      {/* 「Start editing to see some magic happen!」を書き換える */}
      <h2>これから補色調べっ子ちゃんを作るよ!</h2>
    </div>
  );
}
  1. 画面右側のブラウザの文字が変わっていることを確認する
    image.png

入力フォームを作る

色を入力してもらうための入力フォームをつくる

  1. <input>タグを書く

    App.js
    import "./styles.css";
    
    export default function App() {
      return (
        <div className="App">
          <h1>好きな言葉でいいよ!</h1>
          <h2>これから補色調べっ子ちゃんを作るよ!</h2>
          {/* inputを追加する type属性はcolorを選択する */}
          <input type="color" /> 
        </div>
      );
    }
    

    image.png

  2. ユーザーが入力したデータを取得し、状態を保存する
    Reactで画面の状態を管理するためのuseStateフックを用いる
    useStateは引数に任意の値を入れることで、
    その値で初期化した変数と、その変数を更新するための関数をペアで取得することができる

    今回は返却されたペアの名前を、それぞれcolor, setColorとし、
    ユーザーが入力した色情報を保存するために、setColorをinput要素のonChange属性に渡す

    App.js
    import { useState } from "react";
    import "./styles.css";
    
    export default function App() {
      /* 状態を管理するための、値と更新用の関数をペアで取得する */
      const [color, setColor] = useState("");
    
      return (
        <div className="App">
          <h1>好きな言葉でいいよ!</h1>
          <h2>これから補色調べっ子ちゃんを作るよ!</h2>
          {/* 入力フォームの値が変わった時に、その値を保存する */}
          <input type="color" onChange={(event) => setColor(event.target.value)} /> 
        </div>
      );
    }
    

保存した色を表示してみる

  1. 変数colorを<h2>タグで表示してみる

    JSX記法(以下コードのHTMLを書いている部分)では、
    ブラケット({ })で囲むことにより、JavaScriptを書くことができるので、
    変数colorを{ }で囲み、<h2>タグ内に展開する

    App.js
    import { useState } from "react";
    import "./styles.css";
    
    export default function App() {
      const [color, setColor] = useState("");
    
      return (
        <div className="App">
          <h1>好きな言葉でいいよ!</h1>
          <h2>これから補色調べっ子ちゃんを作るよ!</h2>
          {/* 変数colorを展開し、保存した色情報を表示する */}
          <h2>選択中の色: {color}</h2>
          <input type="color" onChange={(event) => setColor(event.target.value)} /> 
        </div>
      );
    }
    

    ブラウザの画面から色を変更すると、選んだ色が16進数(#b83d3dのような形式)で表示されていることがわかる
    image.png

保存した色情報から補色を計算し表示する

  1. 新しくutils.jsというファイルを作成し、以下の補色を計算する関数をコピペする
    (ネットから拾ってきたものなので他の箇所と書き方が異なりますがご容赦ください)

    utils.js
    export const hexToComplimentary = (hex) => {
      // Convert hex to rgb
      // Credit to Denis http://stackoverflow.com/a/36253499/4939630
      var rgb =
        "rgb(" +
        (hex = hex.replace("#", ""))
          .match(new RegExp("(.{" + hex.length / 3 + "})", "g"))
          .map(function (l) {
            return parseInt(hex.length % 2 ? l + l : l, 16);
          })
          .join(",") +
        ")";
    
      // Get array of RGB values
      rgb = rgb.replace(/[^\d,]/g, "").split(",");
    
      var r = rgb[0],
        g = rgb[1],
        b = rgb[2];
    
      // Convert RGB to HSL
      // Adapted from answer by 0x000f http://stackoverflow.com/a/34946092/4939630
      r /= 255.0;
      g /= 255.0;
      b /= 255.0;
      var max = Math.max(r, g, b);
      var min = Math.min(r, g, b);
      var h,
        s,
        l = (max + min) / 2.0;
    
      if (max == min) {
        h = s = 0; //achromatic
      } else {
        var d = max - min;
        s = l > 0.5 ? d / (2.0 - max - min) : d / (max + min);
    
        if (max == r && g >= b) {
          h = (1.0472 * (g - b)) / d;
        } else if (max == r && g < b) {
          h = (1.0472 * (g - b)) / d + 6.2832;
        } else if (max == g) {
          h = (1.0472 * (b - r)) / d + 2.0944;
        } else if (max == b) {
          h = (1.0472 * (r - g)) / d + 4.1888;
        }
      }
    
      h = (h / 6.2832) * 360.0 + 0;
    
      // Shift hue to opposite side of wheel and convert to [0-1] value
      h += 180;
      if (h > 360) {
        h -= 360;
      }
      h /= 360;
    
      // Convert h s and l values into r g and b values
      // Adapted from answer by Mohsen http://stackoverflow.com/a/9493060/4939630
      if (s === 0) {
        r = g = b = l; // achromatic
      } else {
        var hue2rgb = function hue2rgb(p, q, t) {
          if (t < 0) t += 1;
          if (t > 1) t -= 1;
          if (t < 1 / 6) return p + (q - p) * 6 * t;
          if (t < 1 / 2) return q;
          if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
          return p;
        };
    
        var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
        var p = 2 * l - q;
    
        r = hue2rgb(p, q, h + 1 / 3);
        g = hue2rgb(p, q, h);
        b = hue2rgb(p, q, h - 1 / 3);
      }
    
      r = Math.round(r * 255);
      g = Math.round(g * 255);
      b = Math.round(b * 255);
    
      // Convert r b and g values to hex
      rgb = b | (g << 8) | (r << 16);
      return "#" + (0x1000000 | rgb).toString(16).substring(1);
    }
    
    1. で作成した関数をApp.jsで読み込み、先ほどの入力フォームから取得した値から補色を計算して表示する
    App.js
    import { useState } from "react";
    import "./styles.css";
    /* さっき作ったutils.jsの関数を読み込む */
    import { hexToComplimentary } from "./utils";
    
    export default function App() {
          const [color, setColor] = useState("");
    
      return (
        <div className="App">
          <h1>好きな言葉でいいよ!</h1>
          <h2>これから補色調べっ子ちゃんを作るよ!</h2>
          <h2>選択中の色: {color}</h2>
          {/* 補色情報を表示する */}
          <h2>補色: {hexToComplimentary(color)}</h2>
          <input type="color" onChange={(event) => setColor(event.target.value)} /> 
        </div>
      );
    }
    

    image.png

コンポーネントを分ける

Reactを含むコンポーネント指向のフロントエンドライブラリでは、
作った要素をまとまった一つの単位(コンポーネント)として分割することができる

コンポーネントを分割することで、同じデザインや機能を持ったUIを使い回すことができるうえ、
元のファイルを変更すれば、使いまわした箇所全てに適用されるためメンテナンスも容易になる

今回は、「色の入力フォーム」と「結果の表示部分」を別のコンポーネントに切り出してみる

  1. 新しくColorInput.jsというファイルを作成し、App.jsの以下の行を切り取って移動する
    (この時点ではエラーになって大丈夫、画像左のような黄や赤の波線が出ている状態でOK)

    ColorInput.js
    <input type="color" onChange={(event) => setColor(event.target.value)} /> 
    

    image.png

  2. Reactのコンポーネントを作成する
    (この時点ではエラーになって大丈夫)

    コンポーネントはJSXを返却する関数なので、ColorInput.jsを以下のように変更する
    Reactのコンポーネントは頭文字を大文字にするというルールがあるので、関数名はColorInputとする
    ついでに、ラベルも表示しておく

    ColorInput.js
    export const ColorInput = () => {
      return (
        <div>
          <label>色を選択してください</label>
          <input type="color" onChange={(event) => setColor(event.target.value)} /> 
        </div>
      )
    }
    
  3. setColorを受け取れるようにする
    (この時点ではエラーになって大丈夫)

    Reactのコンポーネントでは、コンポーネント外からの値を
    props(propertiesの略)と呼ばれる変数を利用して受け取ることができる
    今回、setColorはこのファイルには存在せず、App.jsに存在しているので、その値を受け取る必要がある
    外部から受け取った値は、propsの中に自動的に格納される

    ColorInput.js
    /* 外部からの値をpropsという変数で受け取れる */
    export const ColorInput = (props) => {
      /* propsからsetColorを取り出す */
      const setColor = props.setColor
      return (
        <div>
          <label>色を選択してください</label>
          <input type="color" onChange={(event) => setColor(event.target.value)} /> 
        </div>
      )
    }
    
  4. ColorInput.jsで作ったColorInputコンポーネントをApp.jsで使用する
    作成したコンポーネントは他のHTML要素のように使用することができる
    propsとして渡したい値は、他の属性と同じように渡すことができる

    App.js
    import { useState } from "react";
    /* さっき作ったColorInput.jsのColorInputコンポーネントを読み込む */
    import { ColorInput } from "./ColorInput";
    import "./styles.css";
    import { hexToComplimentary } from "./utils";
    
    export default function App() {
      const [color, setColor] = useState("");
    
      return (
        <div className="App">
          <h1>好きな言葉でいいよ!</h1>
          <h2>これから補色調べっ子ちゃんを作るよ!</h2>
          <h2>選択中の色: {color}</h2>
          <h2>補色: {hexToComplimentary(color)}</h2>
          {/* 作ったコンポーネントはHTML要素のように使用することができる */}
          {/* setColorを渡す */}
          <ColorInput setColor={setColor} />
        </div>
      );
    }
    

    この時点で、ブラウザで以下のように表示されていればOK
    image.png

  5. 同様に、新しくResult.jsファイルを作り、App.jsの14, 15行目をResultコンポーネントとして切り出す

    注意する点として、コンポーネントでは返却するJSXは必ず1つの要素になっていなければいけない
    そこで、14, 15行目をそのまま返却すると2つ要素になってしまうので、
    React.Fragmentと呼ばれる空のタグ<></>で囲む
    divタグで囲むこともできるが、このFragmentであればHTMLタグとしては判定されないので、
    無駄なタグを作らずに済み、パフォーマンスが良くなる

    Result.js
    /* utils.jsの関数を読み込む */
    import { hexToComplimentary } from "./utils"
    
    export const Result = (props) => {
      /* 外から変数colorを受け取る */
      const color = props.color
      return (
        /* 一つの要素しか返却できないので<></>で囲み一つにする */
        <>
          <h2>選択中の色: {color}</h2>
          <h2>補色: {hexToComplimentary(color)}</h2>
        </>
      )
    }
    
    App.js(ついでに不要な行を削除しています)
    import { useState } from "react";
    import { ColorInput } from "./ColorInput";
    /* さっき作ったResult.jsのResultコンポーネントを読み込む */
    import { Result } from "./Result";
    import "./styles.css";
    
    export default function App() {
      const [color, setColor] = useState("");
    
      return (
        <div className="App">
            {/* 結果の表示部分をResultに置き変える */}
          <Result color={color} />
          <ColorInput setColor={setColor} />
        </div>
      );
    }
    

    以下のようにブラウザに表示されていればOK
    image.png

UIコンポーネントライブラリを利用してオシャレにしよう!

本セクションで実装するもの

  • 補色を利用したデザインのプレビューを表示する機能
    image.png

Chakra UI(UIコンポーネントライブラリ)をインストールする

  1. Chakra UI の Getting Started にアクセスする

  2. Getting Startedの「Installation」にある、以下のコマンドのnpm i以降に書かれた各パッケージ名を、
    CodeSandboxの「Dependencies」というエリアの入力フォームに入力して検索し、
    表示されるパッケージ名を押下する
    image.png
    4つすべてインストールし、以下のように表示されればOK
    image.png

  3. Getting Startedの「Set up Provider」を参考に、以下のようにindex.jsChakraProviderをimportし、<App /><ChakraProvider></ChakraProvider>で囲む

    index.js
    import { StrictMode } from "react";
    import ReactDOM from "react-dom";
    import App from "./App";
    /* ChakraProviderを読み込む  */
    import { ChakraProvider } from "@chakra-ui/react";
    
    const rootElement = document.getElementById("root");
    ReactDOM.render(
      <StrictMode>
          {/* ChakraProviderでAppを囲む */}
        <ChakraProvider>
          <App />
        </ChakraProvider>
      </StrictMode>,
      rootElement
    );
    

Chakra UIのコンポーネントを表示してみる

Chakra UIを含むUIコンポーネントライブラリを利用すると、既に完成したコンポーネントを利用することができる
UIコンポーネントライブラリを使用することで、CSSなどのデザインや凝ったUIのJSの実装を省けるうえ、統一されたデザインのアプリケーションを簡単に作ることができる

Chakra UIのドキュメントを参考に、ボタンを表示してみる

  1. Result.jsにChakra UIのボタンを追加する

    Result.js
    import { hexToComplimentary } from "./utils"
    /* ドキュメントを参考に、importする */
    import { Button } from "@chakra-ui/react"
    
    export const Result = (props) => {
      const color = props.color
      return (
        <>
          <h2>選択中の色: {color}</h2>
          <h2>補色: {hexToComplimentary(color)}</h2>
          <Button colorScheme="blue">Button</Button>
        </>
      )
    }
    

    以下のようにブラウザに表示されればOK
    image.png

Chakra UIのコンポーネントにpropsを渡してみる

UIコンポーネントライブラリのドキュメントには、そのコンポーネントで利用できるpropsの情報が記載されていることが多い

Chakra UIのドキュメントにもコンポーネントのpropsについて記載がある

  1. isLoadingというpropsを渡すとともに、colorSchemeというpropsの値を変更してみる

    Result.js
    import { hexToComplimentary } from "./utils";
    import { Button } from "@chakra-ui/react";
    
    export const Result = (props) => {
      const color = props.color;
      return (
        <>
          <h2>選択中の色: {color}</h2>
          <h2>補色: {hexToComplimentary(color)}</h2>
          {/* isLoadingを追加 colorSchemeの値をblueからorangeに変更 */}
          <Button colorScheme="orange" isLoading={true} >Button</Button>
        </>
      );
    };
    

    以下のようにブラウザに表示されればOK
    isLoadingにtrueを入れたので、ローディングスピナー(ぐるぐる)が表示され、
    colorSchemeをorangeに変更したので、ボタンの色がオレンジになったことがわかる
    image.png

補色を利用したデザインのプレビューを表示する

Chakra UIのコンポーネントには、色を簡単に指定できるpropsが用意されているため、
それを利用して指定した補色を使った場合のUIのプレビューを表示してみる

  1. Result.jsのButtonのpropsを変更し、ユーザーが指定した色とその補色を渡す
    colorというpropsでメインの色、bgというpropsで背景色を指定することができる

    Result.js
    import { hexToComplimentary } from "./utils";
    import { Button } from "@chakra-ui/react";
    
    export const Result = (props) => {
      const color = props.color;
      return (
        <>
          <h2>選択中の色: {color}</h2>
          <h2>補色: {hexToComplimentary(color)}</h2>
          {/* 文字色を指定するcolorにユーザーが選択したcolorを 背景色を指定するbgに補色を入れる */}
          <Button color={color} bg={hexToComplimentary(color)}>
            Button
          </Button>
        </>
      );
    };
    

    以下のようにブラウザに表示されればOK
    image.png

  2. Chakra UIのボタン以外のコンポーネントも表示してみる
    基本的にはドキュメントからコピペするだけで、コンポーネントを使うことができる
    また、CSS in JSという記法でCSSをJSの中に書くこともできる

    Result.js
    import { hexToComplimentary } from "./utils";
    /* 使いたいコンポーネントをimportする */
    import { Box, Button, Circle, Container, Radio, RadioGroup, Slider, SliderFilledTrack, SliderThumb, SliderTrack, Square, Stack, Text } from "@chakra-ui/react";
    
    export const Result = (props) => {
      const color = props.color;
      // 補色を変数に格納する
      const complimentaryColor = hexToComplimentary(color);
      return (
        <>
          <h2>選択中の色: {color}</h2>
          <h2>補色: {complimentaryColor}</h2>
    
          {/* 外枠のコンポーネント */}
          <Container borderColor={color} style={{
            borderWidth: 1,
            borderColor: color,
            borderRadius: 20,
            padding: 20
          }}>
    
            {/* ボタンのコンポーネント */}
            <Button color={color} bg={complimentaryColor}>
              Button
            </Button>
    
            {/* スライダーのコンポーネント */}
            <Slider aria-label="slider-ex-4" defaultValue={30}>
              <SliderTrack bg="gray.200">
                <SliderFilledTrack bg={color} />
              </SliderTrack>
              <SliderThumb boxSize={6}>
                <Box color={complimentaryColor} />
              </SliderThumb>
            </Slider>
    
            {/* ラジオボタンのコンポーネント */}
            <RadioGroup>
              <Stack direction="row">
                <Radio value="1" bg={complimentaryColor}><Text color={color}>First</Text></Radio>
                <Radio value="2" bg={complimentaryColor}><Text color={color}>Second</Text></Radio>
                <Radio value="3" bg={complimentaryColor}><Text color={color}>Third</Text></Radio>
              </Stack>
            </RadioGroup>
    
            {/* 図形のコンポーネント */}
            <Circle size="40px" bg={color}>
              <Square size="20px" bg={complimentaryColor} />
            </Circle>
    
            <Square size="40px" bg={complimentaryColor}>
              <Circle size="20px" bg={color} />
            </Square>
    
          </Container>
        </>
      );
    };
    

    以下のようにブラウザに表示されればOK
    image.png

おわりに

Reactの機能は意外と多くありません。
今回紹介したpropsの受け渡しや、Hooksを利用した状態管理が主な機能です。
なので、実際にReactでアプリケーションを開発する場合には、
ページ遷移を行うためのライブラリや、
APIリクエストをするためのライブラリ、
プログラムのテストを行うライブラリなどを組み合わせることになります。
それぞれの役割を分けて考えると、Reactの開発は理解しやすくなると思います。

この記事が少しでも誰かのお役に立てると幸いです。
間違いを見つけた場合や、もっとこうするとわかりやすいなどのご意見があれば、
ぜひコメントしていただけると嬉しいです。

14
19
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
14
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?