【React】基本

Udemyのこちらの学習教材を通して学んだ、Reactの基礎をまとめました!

この講座はほんとにいいです!これまで何をやってもReactを全然理解できなかった中、辿り着いたこちらの講座に本当に救われました。

モダンJavaScriptの基礎から始める挫折しないためのReact入門
Reactの習得に苦戦する理由は「JavaScript」への理解不足です。このコースではスムーズにReact開発のスタート地点に立てるように、モダンJavaScriptの動作の仕組みや概念、機能から解説します。

以前にも、基礎については以下にまとめていますので、こちらに重複する部分は割愛しています。

Reactの基盤を作成

まずは基盤を作成します。

import React from 'react';

reactって2つ書いてあるけど??

これの意味は、reactというライブラリから、Reactを読み込むという意味

この記述はReact17のアップデートより、JSXの使用だけの場合は記述が不要となりました。

React17のアップデート ???

Reactのアップデート情報はどこから取得すればよいのか?

ここに記載されていました!

Introducing the New JSX Transform – React Blog
Although React 17 doesn’t contain new features, it will provide support for a new version of the JSX transform. In this post, we will describe what it is and ho...

With the new transform, you can use JSX without importing React.

そもそもなぜ必要だったのでしょうか?

JSXに記述したコードがJavaScriptにコンパイルされるのに必要だった。

これが、バージョンアップデートによりデフォルトで機能が組み込まれた。

それでは、Reactの基盤作りに戻りましょう。

HTMLにコンポーネントを反映していくのに必要なreact-domをimportします。

import ReactDom from "react-dom";

// nullという値を返すAppという関数を作成
const App = () => {
  return null;
};

// Appを画面に反映する方法
// renderという関数を使用する
// 第一引数にAppを設定し、コンポーネントとしてレンダリング
// 第二引数にどこに反映していくかを記述。そしてHTMLのidを指定
ReactDom.render(<App />, document.getElementById("root"));
// これでReact開発の基盤ができました!

ReactではJavaScriptの中(JSX)にHTMLを書いていく。

こんなふうに書くことができる。

const App = () => {
  return <h1>Hello World</h1>;
};

return内の記述が複数行になる場合は、( )で囲って書いていく

const App = () => {
  return (
    <h1>Hello World</h1>
  );
};

上記に、要素を一行追加します。

const App = () => {
  return (
    <h1>Hello World</h1>
    <p>How are you</p>
  );
};

すると、以下のエラーとなります。

/src/index.js: Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>?

これはなぜかというと、returnのHTMLは1つのタグで囲わないといけないというルールがあるからです。

そのため、2つの要素をdivタグで囲います。

const App = () => {
  return (
    <div>
      <h1>Hello World</h1>
      <p>How are you</p>
    </div>
  );
};

しかし、このようなエラー回避のためだけにdivを書くのはあまり良くないので、Reactの中のFragmentというものを使用し、同じ役割を果たす事もできる。または空括弧でもOK

const App = () => {
  return (
    <React.Fragment>
      <h1>Hello World</h1>
      <p>How are you</p>
    </React.Fragment>
  );
};

または

const App = () => {
  return (
    <>
      <h1>Hello World</h1>
      <p>How are you</p>
    </>
  );
};

しかし、上記のようにJSXに記述をしていくと、記述量が膨大になってしまいます。

そこで、コンポーネント化をします!

コンポーネントファイルの拡張子は.jsxとします。

コンポーネント化したのがこちら!

import React from "react";
import ReactDom from "react-dom";
import App from "./App";

ReactDom.render(<App />, document.getElementById("root"));

import React from "react";

const App = () => {
  return (
    <>
      <h1>Hello World</h1>
      <p>How are you</p>
    </>
  );
};

export default App;

コンポーネントの命名はパスカルケースとする!

キャメルケースが先頭は小文字であるのに対しパスカルケースは先頭も大文字。

イベントやスタイルの命名には、キャメルケースを使用します。

ボタンクリックでアラートを表示する

クリック時に処理が行われるonClickButtonという関数をAppコンポーネント内に設定します。

const App = () => {
  const onClickButton = () => alert();
  return (
    <>
      <h1>Hello World</h1>
      <p>How are you</p>
      <button onClick={onClickButton}>ボタン</button>
    </>
  );
};

{ }で囲うことによりJavaScriptを書くことを意味している。

スタイルの定義方法

styleの定義の仕方は①直接 と②変数を定義する方法の2つある。

①直接

<h1 style={{ color: 'red' }}>Hello World</h1>

{ }が二重になっているが、styleはオブジェクトで定義するため、内側がオブジェクトの括弧で、外側がJavaScriptを意味している括弧です。

②変数を定義する方法

const App = () => {
  const cotentStyle = {
    color: 'blue',
    fontSize: '18px'
  };
  return (
    <>
      <p style={cotentStyle}>How are you</p>
    </>
  );
};

CSSはキャメルケースで記述する!

定義位置は、コンポーネントの中のreturnの前

Propsを知る

propsとは、コンポーネントに渡す引数的なもののこと。

propsの実用例を見てみます。

ColorfulMessageというコンポーネントを作成し、引数propsを定義します。

App.jsxのJSX内でColorfulMessageの値を定義し、propsを使ってcolorとmessageを変更します。

コードがこちら

import React from "react";
import ColorfulMessage from "./components/ColorfulMessage";

const App = () => {
  const onClickButton = () => alert();
  return (
    <>
      <h1 style={{ color: "red" }}>Hello World</h1>
      <ColorfulMessage color="blue" message="お元気ですか?" />
      <ColorfulMessage color="pink" message="元気です" />
      <button onClick={onClickButton}>ボタン</button>
    </>
  );
};

export default App;

import React from "react";

const ColorfulMessage = (props) => {
  const cotentStyle = {
    color: props.color,
    fontSize: "18px"
  };
  return (
    <>
      <p style={cotentStyle}>{props.message}</p>
    </>
  );
};

export default ColorfulMessage;

propsの中には以下が入っているため、props.colorやprops.messageとすることで値を取得することができます。

{color: "blue", message: "お元気ですか?"}
{color: "pink", message: "元気です"}

引数を取得する他の方法

コンポーネントのタグで囲み、.childrenでその値を取得する事もできます。

childrenを使う方法がこちら。

<ColorfulMessage color="blue">お元気ですか?</ColorfulMessage>
<ColorfulMessage color="pink">元気です</ColorfulMessage>

<p style={cotentStyle}>{props.children}</p>

propsの書き方をスッキリさせる

propsは、上記の通りオブジェクトなので、分割代入を使い、以下のようにpropsの記述を省略することができる。

const ColorfulMessage = (props) => {
  const { color, children } = props;
  const cotentStyle = {
    color: color,
    fontSize: "18px"
  };
  return (
    <>
      <p style={cotentStyle}>{children}</p>
    </>
  );
};

Stateを知る

stateを使う場合、reactのuseStateという関数を使用する。

そしてこのuseStateの中から、変数を配列の分割代入で取り出し、 設定していく 。

配列に定義するのは、stateを使用するための変数名(第一引数)と、更新するための関数名(第二引数)

  const [num, setNum] = useState(0);

useStateの( )の中には初期値を設定できる。

const App = () => {
  const onClickCountUp = () => {
    setNum(num + 1);
  };
  const [num, setNum] = useState(0);

  return (
    <>
      <button onClick={onClickCountUp}>カウントアップ</button>
      <p>{num}</p>
    </>
  );
};

これでボタンがクリックされるとnumが0から+1ずつカウントアップされる。

再レンダリング

ボタンクリックで表示/非表示を切り替える

書き方のコツ

コンポーネント内で使うstateの記述は、定義コンポーネントの直下に記述すると見やすくなる。

論理演算子を使いBooleanで表示条件を設定する。

{showText && <p>表示されたよ!</p>}

左辺がtrueのときに右辺を返す。falseのときに左辺を返す。

参考: ||を使う方法

{showText || <p>表示されたよ!</p>}

左辺がfalseのとき右辺を返す。trueのとき左辺を返す。

参考: よく似たもので??を使う方法

{showText ?? <p>表示されたよ!</p>}

左辺が undefined または null のときに右辺を返す。

つまり、??と||は同じ働きをする。

それでは実際に論理演算子を使ってみましょう!

const App = () => {
  const [showText, setShowText] = useState(true);

  const onClickShowText = () => {
    setShowText(!showText);              ←これによりshowTextが持っているBoolean値の反対に切り替わる
  };

  return (
    <>
      <button onClick={onClickShowText}>on/off</button>
      {showText && <p>表示されたよ!</p>}
    </>
  );
};

上記で作った表示/非表示を3の倍数でのみ表示されるようにする

条件式の書き方NG例

  if (num % 3 === 0) {
    setShowText(true);
  } else {
    setShowText(false);
  }

このようにstateの更新をミスると以下のようなエラーとなるため注意が必要

Too many re-renders. React limits the number of renders to prevent an infinite loop.

なぜ大量の再レンダリングが起きてしまっているのか?

stateが変更されると、処理が先頭に戻り、また上記の条件文に戻ってきた時に同じ処理を繰り返す。

そうならないためにどうすれば良いか。

stateがtrueのとき、falseのときという条件を追加し以下のようにする。

  if (num % 3 === 0) {
    showText || setShowText(true);
  } else {
    showText && setShowText(false);
  }

もう一つ問題がああります!

扱う変数が多くなると、 変数が互いに邪魔しあい、片一方の変数が効かなくなってしまう。

そこで”関心の分離”をする。

使用するのがuseEffect

useEffect

useEffrctの使い方

  useEffect(() => {
    if (num % 3 === 0) {
      showText || setShowText(true);
    } else {
      showText && setShowText(false);
    }
  }, [num]);

useEffectの第二引数に配列を取る。この第二引数の配列を依存配列と言います。

最初の一回だけ通したいような処理を実行する場合は、配列を空配列[ ] とする。

今回の場合、このifの条件式はnumの変数のみで有効としたいため、配列にはnumを記述する。

このnumはカウント数であり、こう記述することによってon/off(showText)に影響を与えないようになる。

上記のような記述をすると、 eslint の警告文(エラーっぽいもの)が表示される。

eslintでの警告文は、useEffectの中で使っている変数は、全て第2引数の[ ]の中で書かないと、バグになる可能性があるという意味。

exportの2パターン

export にはdefaultとそうでないものの2つのパターンがあります。

defaultを使う場合
export default ColorfulMessage;

import側

import ColorfulMessage from "./components/ColorfulMessage";

ちなみに…ここでのColorfulMessageという名称はこのファイル内で任意に付けた名称です。

defaultではない通常のexport

関数コンポーネントの前にexportを付ける

export const ColorfulMessage = (props) => {

この場合のimportは分割代入する必要がある。

import { ColorfulMessage } from "./components/ColorfulMessage";

defaultのimportにに対し、この名称は読み込みファイルのコンポーネントの名称です。

そのため、 defaultではない通常のexport による記述とすることで、typoがあったときにエラーとなり気づくことができるのでこちらを使用するのがおすすめ!

以上、基本についてまとめました!

ご覧いただきありがとうございました。

コメント