okinawa

IT勉強メモ

React基礎

書き途中。

重要部分の抜粋

React扱うなら最低限覚えておきたい部分。

※1、クラスコンポーネントもあるが、ここでは扱わない。

参考サイト

とてもわかりやすい上に、仕組みまで解説してくれる素晴らしい教材だった。
www.udemy.com

サーバー起動方法の忘れ用メモ

下記コマンドを実行する。

cd c:\Users\ユーザー名\Downloads\react-guide-material\react-guide-material\06_control_and_form\src\130_reminder

npm install

npm start

JavaScript基本

ES modulesは別ファイルの読み込み

JavaScriptファイルから別のJavaScriptファイルを読み込む仕組み。

https://www.codegrid.net/articles/2017-es-modules-1/

・エクスポート

export { 関数名1,関数名2,変数名1,変数名2,・・・ } //1ファイルからいくつでもエクスポート可能な記法

default export 関数名や変数名 // 1ファイルから1つだけエクスポートする記法

・インポート

import { 関数名1,関数名2,変数名1,変数名2,・・・ } from "ファイルのパス"//defaultじゃない方

import 関数名や変数名 from "ファイルのパス" //defaultをインポート

オブジェクト、プロパティとは

JavaScriptのオブジェクトはプロパティの集合です。プロパティとは名前(キー)と値(バリュー)が対になったものです。

オブジェクトとは?

// プロパティを持たない空のオブジェクトを作成
const obj = {};

// プロパティを持つオブジェクトを定義する
const obj = {
    // キー: 値
    "key": "value"
};

プロパティとは?

// 
const obj = {
    // ↓これがプロパティ。キーと値がセットになったもの
    key: "value"
};

参考
オブジェクト · JavaScript Primer #jsprimer

メソッドと関数の違い

メソッドは一言で表すと、オブジェクトが持っている関数のこと。

参考
【JavaScriptの入門】関数とメソッド | ワードプレステーマTCD

コールバック関数

コールバック関数とは、引数に渡された関数のこと。

function outLog(callbackFunc) {
  const result = callbackFunc(3);//引数で渡されたコールバック関数を呼び出す
  console.log(result);
}

function multiply(num) {//これが引数に渡される関数。コールバック関数。
  return num * 2;
}

debugger;// ここで処理が止まる便利機能
outLog(multiply);//引数に関数を渡す

map filter

mapは配列の全要素を1つずつ取り出す。for文と同じ。

filterは配列の全要素から条件に合致したものだけ取り出す。

const array = [1,2,3,4,5];

for(let i = 0; i < array.length; i++) {
  console.log(array[i] * 2);
}

//上記のfor文をmapで書く
array.map(val => val * 2);//引数valに配列の全要素が1個ずつ入ってくる
console.log(array.map(val => val * 2));

for(let i = 0; i < array.length; i++) {
  if (array[i] >= 3) {
     console.log(array[i] * 2);
  }
}

//上記のfor文をfilterで書く
array.filter(val => val >= 3);//引数valに配列の全要素が1個ずつ入ってくる
console.log(array.filter(val => val >= 3));

//map filterの複合
const array = [1,2,3,4,5];
array.map(val => val * 2).filter(val => val >=6);//2倍したもので6以上をreturnする
console.log(array.map(val => val * 2).filter(val => val >=6));// 6 8 10

・書き方

map(第1引数=配列の全要素, 第2引数(省略可)=index値, 第3引数(省略可)=配列 => 処理内容);

filter(第1引数=配列の全要素, 第2引数(省略可)=index値, 第3引数(省略可)=配列 => 処理内容);

array.map(val, index, array => { return /*処理内容*/ });

array.filter(val, index, array => { return /*処理内容*/ });

分割代入

分割代入とは配列の要素を1個ずつ変数に代入すること。

//配列
const array = [1,2,3]:
const [a, b, c] = [1,2,3);
const [d, , f} = [1,2,3];//d=1,f=3,eはなし
console.log(d);
console.log(f);

//オブジェクト
const{bbb, aaa} = {aaa:"オブジェクトaaa", bbb:"オブジェクトbbb"};
console.log(aaa);//オブジェクトaaa
console.log(bbb);//オブジェクトbbb

Promise(非同期処理)とは?

resolve()するとthen()の処理に移る。

reject()するとcatch()の処理に移る。

qiita.com

Promiseでのエラーハンドリング

reject()をcatchしないと処理は停止するらしい。(コンソールにエラー文は出る)

ja.javascript.info

React基礎

JSX構文

JavaScriptの構文を拡張したもの。

HTMLに似た構文がコード内で使用できる。

JSX構文で書くとBABELによってReactのcreateElement関数に変換される。→さらにJavaScriptのオブジェクトに変換される。

JSX → createElement関数 → JavaScriptオブジェクト、と変換されていく。

//JSX構文
import React from "react";

const Example = () => {
  return (
    <h1 className="abc">Hello!</h1>
  );
};
console.log(Example());
export default Example;

//BABELで変換後
const Example = React.createElement("h1", {
  className: "abc"
}, "Hello!");

// JavaScriptオブジェクトに変換後
const Exapmle {
  type: h1
  props: {
    chlderen: 'Hello!'
    className: 'abc'
  }
}

コンソール画面

Babel変換サイト↓
Babel · Babel

コンポーネント

画面はコンポーネントという部品でできている。

コンポーネント入れ子可能。

再利用可能。コードが使い回せる。

可読性の向上。変更したいコンポーネント内だけ見ればいいので。

疎結合になる。コンポーネントごとにテスト可能。ただし、 コンポーネント毎の依存度を低くしないとだめっぽい。

コンポーネントJavaScriptの関数として定義する。関数名の頭文字は大文字。 関数コンポーネントと言う。

新規プロジェクトの作成

コマンドプロンプトで下記を実行。

npx create-react-app プロジェクト名 //プロジェクト作成1
npx create-react-app プロジェクト名 --template redux-typescript //プロジェクト作成2 ReduxとTypeScript入りならこっち

npm start //サーバー起動&プロジェクト実行(作成したプロジェクト内にcdコマンドで移動してから)

npm run eject //隠しファイルを表示

pacage.jsonのscriptsに各コマンドの詳細が載っている。

新規プロジェクトの作成2(こっちの方が一般的らしい)

npm create vite@latest

npm install //作成したプロジェクト内にcdコマンドで移動してから)

npm run dev //サーバー起動&プロジェクト実行

CSSの当て方

  • 1,import CSSファイルのパス
  • 2,コンポーネント関数の中でクラス名、ID等を指定。
  • 3,あとはCSS側でクラス名やID等を指定するだけ。

コンポーネントの分け方

Fragment(JSX)

不要なタグを追加したくないときに使う。

JSXでreturnする要素は、1つのルート(最上位)要素でreturnする必要がある。

例えばdiv要素が最上位に2つあるとエラーになる。

最上位に複数の要素を作りたい、かつ不要なタグを追加したくない時にFragmentで囲う。

 <div>aaa</div>
 <div>bbb</div>//これだとエラー

<Fragment>
 <div>aaa</div>//Fragmentで囲えばOK
 <div>bbb</div>
</Fragment>

Fragmentには、クラス名やID名は付けられず。 key属性だけ付けられる。

JSX内でJavascriptを書く

{ }内に式を書くとJavaScriptの式として評価される。

ちなみに式はOKで文はダメ。

const Expression = () => {
    const title = "Expression"
    const array = ['item1','item2','item3']
    const hello = (arg) => `${arg} Function`;
    const jsx = <h3>Hello JSX2</h3>//JSXのオブジェクト扱い
    const bool = true;

    return (
        <div className="expression">
            <h3>Hello {title.toLowerCase()}</h3>
            <h3>{array}</h3>
            <h3>{hello('Hello')}</h3>
            {/* 画面に表示されない*/}
            {<h3>Hello JSX</h3>}
            {jsx}
            {bool}
        </div>

    )
}
式と文の違い

式は、何らかの値を返すもの(変数に代入できるもの)。

文は、変数宣言、for文、if文やセミコロンで区切るもの。

JSXの{ }内で使用できるのは式のみ。

const num = 1; //1は変数に代入できるので式
const a = if(num === a) //if文は変数に代入できないので文
const bool = num === a '一致' : '不一致' //三項演算子の結果は変数に代入可能。式。

props(他のコンポーネントに値を渡す)

ほかコンポーネントに渡す値のことをpropsという。引数のようなイメージ。

特徴1
コンポーネントから子コンポーネントに値を渡す。
基本的には親→子だけ可能で、子→親に値を渡すことは出来ない。

特徴2
propsは読み取り専用。
親から子に渡された値(props)を子側で変更するのは不可。
constと同じで再代入不可ということ。

キーワード:分割代入
分割代入は、オブジェクトからプロパティを取り出す機能。

コンポーネント(Example.js)↓

import Child from "./components/Child";

const Example = () => {
    const hello = (arg) => `Hello ${arg}`;
    // const o = {
    //     color: "red",
    //     num: 123
    // }
    return (
        <>
            <Child 
                // POINT propsには全てのタイプの値を渡すことができます。
                // {...o}
                color="blue"
                fn={hello}
                bool
                obj={{ name: 'Tom', age: 18 }}
            />
            <Child color="red" />
        </>
    )
};

export default Example;

コンポーネント(Child.js)

import "./Child.css";

const Child = ({color: c = 'green', num, fn, bool, obj}) => {//ここでExample.jsから渡された値を受け取る。=の後はデフォルト値(なくてもよい)。分割代入と言う。
  return (
    <div className={`component ${c}`}>
      <h3>Hello Component</h3>
      <h3>{num}</h3>
      <h3>{fn('Props')}</h3>
      <h3>{ bool ? 'true' : 'false'}</h3>
      <h3>{ obj.name + obj.age }</h3>
    </div>
  );
};

export default Child;
props.childerenとは

コンポーネントを丸ごと別のコンポーネントに渡したい時に使う。

今回の例だとContainerコンポーネントにProfileコンポーネントを渡している。

画像だとContainerが金色の枠線。Profileが中身で、これがchildrenに当たる。↓

children

Example.js
Container.jsにProfile.jsのプロパティを渡している。

import Profile from "./components/Profile";
import Container from "./components/Container";

const profile = [
  { name: "Takashi", age: 19, country: "Japan" },
  { name: "Jane", age: 28, country: "UK", color: "red" },
];

const Example = () => {
  return (
    <div>
      {/* 書き方1 */}
      <Container title="Childrenとは?" >
        <Profile {...profile[0]}/>
        <Profile {...profile[1]}/>
      </Container>

      {/* 書き方2 */}
      <Container title="Childrenとは?" children={
        [
          <Profile key={profile[0].name}{...profile[0]}/>,
          <Profile key={profile[1].name}{...profile[1]}/>
        ]
      }

      // 書き方3(分けて渡したいとき用)
      children2={<Profile key={profile[0].name}{...profile[0]}/>}
      children3={<Profile key={profile[1].name}{...profile[1]}/>}
      />
    </div>
  );
};

export default Example;

Container.js
Profile.jsのプロパティをExample.jsから受取。

import "./Container.css";

const Container = ({ title, children, children2, children3 }) => {
  return (
    <div className="container">
      <h3>{title}</h3>
      {children}
      {children2}
      {children3}
    </div>
  );
};

export default Container;

Profile.js
Container.jsに渡される子コンポーネント

import "./Profile.css";

const Profile = ({ name, age, country, color }) => {
  return (
    <div className={`profile ${color}`}>
      <h3>Name: {name}</h3>
      <p>Age: {age} </p>
      <p>From: {country}</p>
    </div>
  );
};

export default Profile;

イベントと状態

イベント

書き方の基本

イベント名={ 処理内容 }

const Example = () => {

  const clickHandler = () => {
    alert('ボタンクリック');
  }


  return (

    <button onClick={clickHandler}>クリックしてね</button>
    <div>
      <label>
        入力値のイベント:
        <input
          type="text"
          onChange={() => console.log("onChange検知")}
          onBlur={() => console.log("onBlur検知")}
          onFocus={() => console.log("onFocus検知")}
        />
      </label>
    </div>
  );
};

export default Example;
状態(state)

状態というのは何らかの値のこと。

値を保持する。変数とは別物。

・基本の書き方

import { useState } from 'react';
//useStateは[ 状態用変数、状態更新用関数 ]を返す。
const [状態用変数、状態更新用関数] = useState(/*引数=状態用変数の初期値*/);

・サンプル

import { useState } from 'react'
const Example = () => {
  //useStateは[ 状態用変数、状態更新用関数 ]を返す
  const [count, setCount] = useState(0);//状態用変数countの初期値0で呼び出し
  const clickButton = () => {
    return setCount(count + 1);//状態更新用関数setCountで状態用変数countを更新する
  };
  return (
    <>
      <p>クリック回数:{count}</p>
      <button onClick={clickButton}>+</button>
    </>
  );
};

export default Example;
変数と状態の違いは?

状態を変更すると、画面が再描画される。

画面更新(F5)しても値が保持されるのが特徴。

ReactでのStateと変数の違いと使い分け | MaxaBlog

状態の更新は即時ではない

状態の更新をまず予約し、再レンダリング後に状態が確定する。

状態更新を予約 → 再レンダリング → 状態確定

例:ボタンを押すと数字をプラス1される
setcount(count + 1);を2つ書いているので、プラス2されそうだが、実際にはされない。
なぜなら、状態変数countは初期値で、下記の流れで処理されるから。

count + 1(状態更新を予約。この時点ではcount=0なので、0+1で予約はcount=1)
count + 1(状態更新を予約。この時点ではcount=0なので、0+1で予約はcount=1)
Exampleコンポーネント実行(再レンダリング)
countが1に確定(状態確定。count=1)

つまり「0 + 1」を2回実行していることになる。

import { useState } from "react";

const Example = () => {
    const [count, setcount] = useState(0);
    const countUp = () => {
        setcount(count + 1);
        setcount(count + 1);//プラス2されそうに見えるがされない
        // setcount(prevCount => { return prevCount + 1 }); ←こう書かないとプラス2されない
    };

  return(
    <>
        <p>現在のカウント数: {count}</p>
        <button onClick={countUp}>+</button>
        
    </>
  )
};

export default Example;
オブジェクト型&配列の状態(state)変更時の注意点

1.オブジェクト型のステート変更する時は全プロパティを変更する

2.オブジェクト型&配列のステート変更時は、新しいオブジェクトを渡す

const Example = () => {
    const humanObj = { name: "John", age: 20 };
    const [human, setHuman] = useState( { name: "John", age: 20 })

    const numArray = { 1,2,3 };
    const { nums, setNums } = useState(numArray);
  };


  const changeName = (e) => {
    //1.オブジェクト型のステート変更する時は全プロパティを変更する
    setHuman({ name: e.target.value  })//ageプロパティがないのでダメ
    setHuman({ name: e.target.value, age: human.age })//OK
    setHuman({ ...human, name: e.target.value,  }) //スプレッド演算子。プロパティが多い時はこれが便利。

    //2.オブジェクト型のステート変更時は、新しいオブジェクトを渡す
    human.name = e.target.value;
    setPerson(human);//humanオブジェクトを使いまわしているのでダメ
    setHuman({ name: e.target.value, age: human.age })//OK

    //2.配列のステート変更時は、新しいオブジェクトを渡す
    nums = [ 4,5,6 ];
    setNums(nums);//nums配列を使いまわしているのでダメ
    setNums([ ...nums ]) //OK。スプレッド演算子。nums配列の中身を展開している。
  }
ReactでgetElementBy~が使われないのなぜ?

多分ステートがあるから。

例えば、textareaの入力をspanにコピーする場合もステートで十分。

state使用例

import { useState } from "react";
const Example = () => {

  const [textArea, setTextArea] = useState("");

    //テキスト入力をステートにセット
    const changeTextArea = (e) => {
      setTextArea(e.target.value);
    }
 
  return (
    <>
// テキストエリアの入力をspanにコピー
      <p><textarea value={textArea} onChange={changeTextArea}></textarea></p>
      <p><span>{textArea}</span></p>
    </>
  );
};

export default Example;
状態(state)特徴・注意点まとめ

ここらへんの仕組みは参考教材の動画がわかりやすいので要参照。

■特徴

  • ステートが変わると再レンダリングされる(重要!!!)
  • ステートは再レンダリング後も保持。F5で画面全体再更新すると消える。
  • ステートはコンポーネント毎に保持
  • ステートはpropsで渡せる
  • ステートを更新する時は更新用関数を使う

■注意点

  • コンポーネントの中で呼び出す
  • if/for文の中で呼び出さない
  • 状態更新は即時ではない(予約)
  • オブジェクト型のステート変更する時は全プロパティを変更する
  • オブジェクト型と配列のステート変更時は、新しいオブジェクトを渡す
  • コンポーネントが消えるとステートも初期化される
【重要】Stateが変わると再レンダリングされるってどういうこと?

テキスト入力すると、stateが変わる。

stateが変わる度に再レンダリング、つまりExample関数コンポーネントが再実行されている!

ここは覚えておきましょう。

import { useState } from 'react';

//Stateが更新されるとExample関数が再実行される
const Example = () => {
  const [state, setState] = useState("");

// state更新関数
  const setText = (e) => {
    setState(e.target.value);
  }

  return (
    <>
    // state更新関数をonChangeで呼び出し
      <input type="text" onChange={setText} />
      <p>{state}</p>
    </>

  );
};
【重要】逆にStateが変わらないと、値が変わっても画面に反映されない

↑コンソールではnonStateの値更新が確認できるが、画面には反映されず0のまま。

import { useState } from 'react';

//Stateが更新されるとExample関数が再実行される
const Example = () => {
  const [state2, setState2] = useState(0);

// state更新関数
  const countUp2 = () => {
    console.log(1 + state2 + ` = state2`)
    setState2(prev => prev + 1);
  }
  
// 普通の変数更新関数
  let nonState = 0;
  const countUp = () => {
    nonState += 1
    console.log('nonState = ' + nonState)
    return nonState;
  }

  return (
    <>
      <p>{state2}</p>
      <button onClick={countUp2}>state+1</button>
      <p>{nonState}</p>
      <button onClick={countUp}>nonState+1</button>
    </>

  );
};

ちなみに、nonState更新 → state2更新

で再レンダリングしてもnoStateが反映されないのは、state2更新の度にExample 関数全体が実行されるので、

let nonState = 0;

で初期化されるから。

Stateは再レンダリング後も保持されるので画面に反映される。

普通のJavaScriptとは感覚が違うのねえ。

制御構文とフォームの制御

配列をリスト表示

map関数を使う。

const numArray = [1, 3, 5]

// 中略
return (
<ul>
 {numArray.map((num) => <li>{num}</li>)}
</ul>
);
リストにはkeyをつける

ここは文字だと分かりづらいので、参考教材の動画を要参照。

keyを付けないと警告が出る↓

console

・keyを付ける理由

keyをつけないとリストの一部だけ更新した場合でも、リストの要素が全て更新されてしまうから。

Reactは要素ツリーの差分を検出して、DOMを更新している。

しかし、リストにkeyをつけないと要素を特定できないため、全更新になる。

・keyの注意点

keyには一意の値をつける。(同一ツリー内で一意ならOK)

keyにはなるべくIndex値をつけない。

const numArray = [1, 3, 5]

// 中略
return (
<ul>
 {numArray.map((num) => <li key={num}>{num}</li>)}//ここでkey
</ul>
);
色々なif条件(if && ?? 3項演算子)

&&はtrueの場合のみ、&&の右の値を表示。

??はnullかudefinedなら、??の右の値を表示。それ以外なら変数の値をそのまま表示。

const Example = () => {
  const flag = true;
  const hoge = "入っています";
  const hoge2 = undefined;
  return (
    <>
      <p>{flag && "true"}</p>//&&記法
      <p>{flag ? "true" : "false"}</p>//三項演算子
      <p>{hoge ?? "null or undefined"}</p>//??記法。入っています
      <p>{hoge2 ?? "null or undefined"}</p>//??記法。null or undefined
    </>
    );
  };

ReactJSのJSX内で条件式の書き方を3つ紹介【使いやすい順に解説】 #React - Qiita

input要素

基本的にはHTMLと同じ。

import {useState} from "react";
const Example = () => {
  const [text, setText] = useState();
  return (
    <div>
      <label htmlFor="aaa">ラベル</label>
      <p>
        <input
          id="aaa"
          placeholder="入力サンプル"
          // value="aaa"
        />
      </p>
    </div>
  );
};

export default Example;