書き途中。
- 重要部分の抜粋
- 参考サイト
- サーバー起動方法の忘れ用メモ
- JavaScript基本
- React基礎
重要部分の抜粋
React扱うなら最低限覚えておきたい部分。
- コンポーネント=関数コンポーネントであり、その名の通り関数。※1
- 状態(State)が更新されると、再レンダリング=関数コンポーネントが再実行される。
- JSXで
<Child />
はChild関数コンポーネントの実行を意味する。 - 親コンポーネントが再レンダリングされると、子コンポーネントも再レンダリング。
※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()の処理に移る。
Promiseでのエラーハンドリング
reject()をcatchしないと処理は停止するらしい。(コンソールにエラー文は出る)
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,jsファイルを作成。コンポーネント関数で何らかの画面部品を作る。
- 2,export { コンポーネント関数名 }
- 3,使いたいファイルで「import { コンポーネント関数名 } from "jsファイルのパス"」
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に当たる。↓
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にコピーする場合もステートで十分。
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を付けないと警告が出る↓
・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;