📖

Reactの基礎

2022/05/10に公開

JSXについて

React で JSX を使うことは必須ではありません。
しかし、JSX を使うと React 要素をより簡便な形式で作成できます。
JSX は JavaScript の拡張言語であり、HTMLライクな記述 + JavaScriptの構文が使える。
結局、JSXはJavaScriptというプログラミング言語とHTMLというドキュメント言語を2つ掛け合わせて使えるようにしたもの。

JSX記法のルールについて

index.js
import React from "react";
import ReacrDom from "react-dom";

 const App () => {
   return (
      <>
        <h1>こんにちは!</h1>
        <p>お元気ですか?</p>
      </>
   );
};
ReactDom.render(<App />, document.getElementById("root"));

コンポーネント、Props、Stateについて

コンポーネント・・・画面要素の1単位。1つのWEBページの全てを表示させることもできるし、テキストボックスなどの一部を表示させることもできる。
Props・・・コンポーネントに渡される引数みたいなもの。
State・・・各コンポーネントが持つ状態。stateが変更されると再レンダリングされる。

コンポーネントの使い方

return内にHTMLタグを長々と記載していくと見づらくなっていくので、いろんなファイルに分けてコンポーネントとして管理していく。
下記では、コンポーネント化したApp.jsをindex.jsでインポートして使用している。
index.js:コンポーネント化したApp.jsをimportして使用している。
App.js:画面のレンダリング部分(return内のHTMLタグ)をコンポーネント化している。

index.js
import React from "react";
import ReacrDom from "react-dom";
import App from "./App";//App.jsをimportして使えるようにしている。

ReactDom.render(<App />, document.getElementById("root"));
App.js
import React from "react";

const App = () => {
   return (
      <>
        <h1>こんにちは!</h1>
        <p>お元気ですか?</p>
      </>
   );
};

export default App;
//exportすることによってこのファイル(App.jsx)を他のファイルで使用することができる。

ファイル名は.jsxでも.jsでも問題ないが、コンポーネント化したファイルは.jsxにしたほうが良い。

コンポーネントの命名規則について

先頭が大文字で始まり、単語の区切りを大文字とする変数名の付け方を「パスカルケース」と呼びます。
Reactのコンポーネントはこのパスカルケースで命名しましょう!

Reactでのイベントやstyleの扱い方

App.jsx
import React from "react";

const App = () => {
  const OnclickButton = () => alert();
  const contentstyle = {
    color: "blue"
    fontSize: "18px"
  };
   return (
      <>
        <h1 style={{ color: "red"}}>こんにちは!</h1>
        <p style={contentStyle}>お元気ですか?</p>
        <button onClick={onClickButton}>ボタン</button>
      </>
   );
};

export default App;

<h1></h1>タグは、直接オブジェクトをタグ内に記載している(タグに埋め込む形)
<p></p>タグは、オブジェクトの変数を定義して、CSSのプロパティの内容をスタイルに反映している。
ボタンをクリックするとonClickイベントが発生、関数{onClickbutton}が呼び出されてアラートが表示される。

Propsについて

App-pattern1.jsx
//App.js(パターン1)
import React from "react";
import ColofulMessage from "./components/ColorfulMessage-pattern1";

const App = () => {
  const OnclickButton = () => alert();
   return (
      <>
        <ColofulMessage color="pink" message="元気です"/>
      </>
   );
};

export default App;

ColofulMessage.jsxのpropsにcolorとmessageを渡している。
colorとmessageは、オブジェクトのプロパティとしてpropsに渡している。

ColorfulMessage-pattern1.jsx
import React from "react";
//console.log(props)
//コンソールログで出力するとpropsの中身(オブジェクトのプロパティ)colorとMessageが表示される。
const App = () => {
  const ColofulMessage = (props) => {
  const contentStyle = {
    color: props.color,
    fontSize: "18px"
  };

  return <p style={contentStyle}>{props.message}</p>;
};

export default ColofulMessage;

App-pattern1.jsxのcolor="pink" message="元気です"が、
ColorfulMessage-pattern1.jsxのprops.colorとprops.message部分に反映されて
ブラウザ画面に出力される。

App-pattern2.jsx
//App.js(パターン1)
import React from "react";
import ColofulMessage from "./components/ColorfulMessage-pattern2";

const App = () => {
  const OnclickButton = () => alert();
   return (
      <>
        <ColofulMessage color="pink">元気です</ColofulMessage>
      </>
   );
};

export default App;

パターン1:<ColofulMessage color="pink" message="元気です"/>
パターン2:<ColofulMessage color="pink">元気です</ColofulMessage>
パターン2ではメッセージ部分を<ColofulMessage></ColofulMessage>のタグで囲っている。
タグで囲った内容は、Childrenの要素に入る。

ColorfulMessage-pattern2.jsx
import React from "react";
const { color, children } = props;

const App = () => {
  const ColofulMessage = (props) => {
  const contentStyle = {
    color: color,
    fontSize: "18px"
  };

  return <p style={contentStyle}>{children}</p>;
};

export default ColofulMessage;

const { color, children } = props;部分では、分割代入を使いオブジェクトpropsのcolorとchildrenの要素を抜き出す。

オブジェクトのプロパティ名(color)と値に指定する変数名(color)が同じ場合propsを省略できる。
つまり、分割代入で抜き出すことによってパターン1のようにcolor: props.color, → color: color, に書き換えることが可能になる。

return <p style={contentStyle}>{children}</p>;部分では、
分割代入で抜き出すことによってprops.childrenではなくchildrenとして値を使える。
また、分割代入しなかった場合、タグで囲った中身をprops.childrenとして渡すこともできる。

Stateについて(useState)

AppState.jsx
import React, { useState } from "react";
//useStateを使う場合、importする構文が少し変わる
import ColofulMessage from "./components/ColorfulMessage-pattern2";

const App = () => {
  const onClickCountUp = () => {
    setNum(num + 1);
    //説明1
  };
  const [num, setNum] = useState(0);
  //説明2
  return
      <>
        <h1 style={{ color: "red"}}>カウントアップ機能</h1>
        <button onClick={onClickCountUp}>カウントアップ!</button>
        <p>{num}</p>
	//説明3
      </>
   );
};

export default App;

ボタンをクリックすると、数字がカウントアップしていく機能を実装。
また、ColorfulMessage-pattern2をインポートしている。(特に問題ないのでそのまま使用)

再レンダリングの副作用とuseEffectについて

AppRendering.jsx
import React, { useState } from "react";
import ColofulMessage from "./components/ColorfulMessage-pattern3";

const App = () => {
  console.log("AppRendering.jsxレンダリング確認");
  //説明1
  const [num, setNum] = useState(0);
  const [helloFlag, setHelloFlag] = useState(true);
  //説明2

  const onClickCountUp = () => {
    setNum(num + 1);   
  };

  const onSwitchHelloFlag = () => {
    setHelloFlag(!helloFlag);   
  };

  return (
      <>
        <ColofulMessage color="blue">カウントアップ機能</ColofulMessage>
        <button onClick={onClickCountUp}>カウントアップ!</button>
        <p>{num}</p>
        <br />
        <button onClick={onSwitchHelloFlag}>on/off</button>
        //説明3
        {helloFlag && <p>hello!</p>}
	//説明4
      </>
   );
};

export default App;
ColorfulMessage-pattern3.jsx
import React from "react";

const ColofulMessage = (props) => {
  console.log("ColorfulMessage-pattern3.jsxレンダリング確認");
  //説明5

  const { color, children } = props;
  const contentStyle = {
    color,
    fontSize: "18px"
  };

  return <p style={contentStyle}>{children}</p>;
};

export default ColofulMessage;
AppRendering-error.jsx
import React, { useState } from "react";
import ColofulMessage from "./components/ColorfulMessage-pattern3";

const App = () => {
  console.log("AppRendering-error.jsxレンダリング確認");
  const [num, setNum] = useState(0);
  const [helloFlag, setHelloFlag] = useState(true);

  const onClickCountUp = () => {
    setNum(num + 1);   
  };

  const onSwitchHelloFlag = () => {
    setHelloFlag(!helloFlag);   
  };
  
  if (num % 3 === 0) {
    setHelloFlag(true);
  } else {
    setHelloFlag(false);
    //説明1
  }

  return (
      <>
        <ColofulMessage color="blue">カウントアップ機能</ColofulMessage>
        <button onClick={onClickCountUp}>カウントアップ!</button>
        <p>{num}</p>
        <br />
        <button onClick={onSwitchHelloFlag}>on/off</button>
        {helloFlag && <p>hello!</p>}
      </>
   );
};

export default App;
AppRendering-error-fix.jsx
import React, { useState } from "react";
import ColofulMessage from "./components/ColorfulMessage-pattern3";

const App = () => {
  console.log("AppRendering-error-fix.jsxレンダリング確認");
  const [num, setNum] = useState(0);
  const [helloFlag, setHelloFlag] = useState(false);

  const onClickCountUp = () => {
    setNum(num + 1);   
  };

  const onSwitchHelloFlag = () => {
    setHelloFlag(!helloFlag);   
  };
  
if (num > 0) {
  if (num % 3 === 0) {
    helloFlag || setHelloFlag(true);
    //説明1
  } else {
    helloFlag && setHelloFlag(false);
    //説明2
  }
}

  return (
      <>
        <ColofulMessage color="blue">カウントアップ機能</ColofulMessage>
        <button onClick={onClickCountUp}>カウントアップ!</button>
        <p>{num}</p>
        <br />
        <button onClick={onSwitchHelloFlag}>on/off</button>
        {helloFlag && <p>hello!</p>}
      </>
   );
};

export default App;
AppRendering-useEffect.jsx
import React, { useEffect, useState } from "react";
//説明1
import ColofulMessage from "./components/ColorfulMessage-pattern3";

const App = () => {
  console.log("AppRendering-useEffect.jsxレンダリング確認");
  const [num, setNum] = useState(0);
  const [helloFlag, setHelloFlag] = useState(false);

  const onClickCountUp = () => {
    setNum(num + 1);   
  };

  const onSwitchHelloFlag = () => {
    setHelloFlag(!helloFlag);   
  };
  
useEffec(() => {
  console.log("useEffect確認");
  //説明2
if (num > 0) {
  if (num % 3 === 0) {
    helloFlag || setHelloFlag(true);
  } else {
    helloFlag && setHelloFlag(false);
  }
}
}, [num]);
//説明3
  return (
      <>
        <ColofulMessage color="blue">カウントアップ機能</ColofulMessage>
        <button onClick={onClickCountUp}>カウントアップ!</button>
        <p>{num}</p>
        <br />
        <button onClick={onSwitchHelloFlag}>on/off</button>
        {helloFlag && <p>hello!</p>}
      </>
   );
};

export default App;

静的構文解析ツールのESLintで下記エラーが出た場合の対処方

AppRendering-useEffect.jsx
/*eslint react-hooks/exhaustive-deps: off*/
//説明1
import React, { useEffect, useState } from "react";
import ColofulMessage from "./components/ColorfulMessage-pattern3";

const App = () => {
  console.log("AppRendering-useEffect.jsxレンダリング確認");
  const [num, setNum] = useState(0);
  const [helloFlag, setHelloFlag] = useState(false);

  const onClickCountUp = () => {
    setNum(num + 1);   
  };

  const onSwitchHelloFlag = () => {
    setHelloFlag(!helloFlag);   
  };
  
useEffec(() => {
  console.log("useEffect確認");

if (num > 0) {
  if (num % 3 === 0) {
    helloFlag || setHelloFlag(true);
  } else {
    helloFlag && setHelloFlag(false);
  }
}
//eslint-disable-next-line
//説明2
}, [num]);

  return (
      <>
        <ColofulMessage color="blue">カウントアップ機能</ColofulMessage>
        <button onClick={onClickCountUp}>カウントアップ!</button>
        <p>{num}</p>
        <br />
        <button onClick={onSwitchHelloFlag}>on/off</button>
        {helloFlag && <p>hello!</p>}
      </>
   );
};
export default App;

default exportとexport

ColorfulMessage-not-default.jsx
//ファイルをexportする方
import React from "react";
export const ColofulMessage = (props) => {
//説明1
  console.log("ColorfulMessage-not-default.jsxレンダリング確認");

  const { color, children } = props;
  const contentStyle = {
    color,
    fontSize: "18px"
  };

  return <p style={contentStyle}>{children}</p>;
};

//export default ColorfulMessage-not-default;
//説明2
App-not-default.jsx
//ファイルをimportする方
import React, { useState } from "react";
import {ColofulMessage} from "./components/ColorfulMessage-not-default";
//説明1

const App = () => {
  console.log("App.jsレンダリング確認");
  const [num, setNum] = useState(0);
  const [helloFlag, setHelloFlag] = useState(true);

  const onClickCountUp = () => {
    setNum(num + 1);   
  };
------以下のコードは省略------

クラスコンポーネントは必要なのか?

結論から言うと、新規のプロジェクトはクラスコンポーネントは不要!

もともと、クラスコンポーネントと関数コンポーネントは、明確な使い分けがあった。
stateが使える(管理できる)のはクラスコンポーネントだけで
関数コンポーネントはpropsを受け取ってなにかするという認識だったため、
stateを含むのならクラスコンポーネント、
それ以外なら関数コンポーネントで作成しましょうといった感じが王道のreactの使い方だった。

しかし、react hooksの登場で関数コンポーネントでもstateが使えるようになった。
クラスコンポーネントの勉強を頑張って勉強する必要はないが、古いプロジェクトにあたった場合、クラスコンポーネントに触れる可能性はある。

Discussion