Reactを動かす
<!DOCTYPE html>
<html>
<head>
<script src="/libs/react.development.js"></script>
<script src="/libs/react-dom.development.js"></script>
<script src="/libs/babel-standalone.js"></script>
</head>
<body>
<div id="app"></div>
<script type="text/babel">
// jsでタグは読み込まれないので、javascriptのオブジェクトに変換する際にバベルを使ってjavascriptのコードを変換して使用
const appEl = document.querySelector('#app');
const root =ReactDOM.createRoot(appEl);
root.render(<h1>こんにちは</h1>);//jsx構文
//予期せぬ文字列となっている:jsで読み込まれない。
// v18以降はroot.renderが推奨
// 下記は非推奨
// ReactDOM.render(<h1>こんにちは</h1>,appEl);
</script>
</body>
</html>
コンポーネント:
画面の各構成要素をReactで定義したもの
・再利用の向上
・可読性の向上
・疎結合になる(バグの減少)
コンポーネントはJSの関数定義
function Welcome(){
return <h1>Hello</h1>;
}
<Welcome />
<!DOCTYPE html>
<html>
<head>
<script src="/libs/react.development.js"></script>
<script src="/libs/react-dom.development.js"></script>
<script src="/libs/babel-standalone.js"></script>
</head>
<body>
<div id="app"></div>
<script type="text/babel">
const appEl = document.querySelector('#app');
const root = ReactDOM.createRoot(appEl);
function Example(){//必ず関数の頭は大文字、小文字だとhtmlのタグと認識される。
return <h1>Hello Components</h1>; //関数コンポーネント
}
// const Example2 =() =>{
// return <h1>Hello Components2</h1>
// }
// 1行の時
const Example2 =() => <h1>Hello Components2</h1>
//複数行の時
const Example3 =() =>{
return (
<div>
<h1>Hello Components2</h1>
</div>
)
}
//下記でもOK,{}なしでもreturn のみなので不要
const Example4 =() => (
<div>
<h1>Hello Components2</h1>
</div>
)
const a =() =>{
return //何も続けなかった場合にjavascriptエンジンが "return undefined;"のセミコロンが代入されているのと同じことになり、undefineとなり、実行文章が終えることと同じ意味になるため、改行と同じ意味になります。
// 複数行である場合には()をつけるようにする。
"戻り値";
}
console.log(a())
root.render(<Example2 />);
</script>
</body>
</html>
React 立ち上げ
# プロジェクトの作成方法
npx create-react-app {プロジェクト名}
# create-react-appドキュメント
npm docs create-react-app
Windowsの方でエラーが発生する方は以下のコマンドを実行してみてください。
```powershell
Set-ExecutionPolicy RemoteSigned
その他
Vite というモジュールバンドラーを使ったプロジェクトの作成
最近は一般的
npm create vite@latest
"scripts": {
"start": "react-scripts start",
//開発時に使うコマンドでサーバーを立ち上げアプリを使う
"build": "react-scripts build",
//本番環境用にビルドするコマンド
"test": "react-scripts test",
//テストスクリプトを実行するようのコマンド
"eject": "react-scripts eject"
//隠しファイルを表示する用のコマンド
},
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint src --ext js,jsx --report-unused-disable-directives --max-warnings 0",
//コードチェック
"preview": "vite preview"
},
React スタイル
import "./Example.css";
class MyClass{}//<<JSでは左のように使うため。混同しないように
const Example = () => {
return (
<div className="component">
{/* classではなくclassNmae */}
<h3>Hello Component</h3>
</div>
);
};
export default Example;
.App-start .component{
padding:1rem;
color:red;
border:5px solid green
}
/* cssはグローバルになるため、CSSを当てる際には注意が必要 */
パーツを分割
import Child from "./component/Child";
// .jsはどちらでも良いwebpackが勝手に解釈してくれる
import Child from "./components/Child"
const Example = () => <Child />;
export default Example;
const Child = () => {
return (
<div className="component">
<h3>Child Component</h3>
</div>
);
}
//コンポーネントは一つのファイルに一つのコンポーネントが普通
//export default でOK
export default Child
フラグメント
import "./Child.css";
// import React from "react" //どちらでも良い
//この場合には<React.Fragment>で囲む
import { Fragment } from "react"; //どちらでも良い
const Child = () => {
return (
// ルート要素として一つのルートで囲む必要がある。
// divなど不要なタグで囲まないようにするためにFragmentを使う
//fragmentは属性をつけることができない
<Fragment key="">
{/* キー属性はつけることが可能、ただし、Fragmentのキーワードは省略不可 */}
{/* <>でOK */}
<div className="component">
<h3>Hello Component</h3>
</div>
<h3>Hello Fragment</h3>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati repellat dolor doloribus iure consequatur soluta? Optio corrupti ratione suscipit recusandae eius perspiciatis illo corporis? Aliquam nam repellendus quos expedita est?</p>
</Fragment>
);
};
export default Child;
ReactのJS実行
JSのコード内では波括弧を使ってJAVASCRIPTの指揮を評価してその結果を画面上に表示する。
import "./Expression.css"
const Expression = () => {
const title = "Expression";
const arry = ['item1', 'item2', 'item3'];
const hello = (arg) => `${arg} function`; //`${arg}`:テンプレートリテラル
const jsx = <h3>Helloe JSX</h3>;//Javascriptのオブジェクトとして使われる。
const bool = true;
return (
<div className={title.toLowerCase()}>
{/* タイトルを使って小文字表示 メソッドも実行可能*/}
<h3>Hello {title}</h3>
<h3>Hello {arry}</h3>
{/* 配列の場合自動的に展開されて表示する */}
<h3>{hello('Hello')}</h3>
<h3>{/* 画面上に表示されません。 */}</h3>
{<h3>Helloe JSX</h3>}
{/*これも JS コード 最終的にJSのオブジェクトに変換される。 */}
{bool}
{/* boolearnは表示されない。 */}
</div>
);
//jsのコードを埋め込むことができる。式を埋め込み可能
}
export default Expression;
式と文
JSX内では式しか使うことができない。
式:何らかの値を返すもの(変数に代入できるもの)
文:変数宣言、for文、if文、switch文やセミコロンで区切るもの。
import "./Child.css";
const Child = () => {
const fn = () => 'hello';
const a =if (true) { 'hello' };//NG
// if文自体は変数に代入できないものなので文となる。
const f = fn();
//関数を実行した結果はhelloという値を返す式となりますので、この関数の実行結果は式
const c = 1 === 1;
//式 左オペランドと右オペラんどが等しい場合にはtrue/falseを返す式となります。
//ただし、表示はされない
const b = 1;
// const b = 1;は文になる。
// 1というのは1という値を返す式、変数に代入できる。
1;//式にも文にもなりえる 式ぶん
if (true) { 'hello' };
// ここでif文はOK
return (
<div className="component">
<h3>式と文</h3>
{1 === 1}
{/* 非表示い */}
{true ? 'hello' : 'bye'}
{/* OK */}
{if (true) {'hello'};}
{/* NG for も同様 return内で使わなければOK */}
</div>
);
};
export default Child;
const title = 'Expression';
const array = ['item1', 'item2', 'item3'];
const fn = (arg) => {
return `${arg} Function`;
};
const upperCaseText = 'upperCaseText';
const Example = () => {
return (
<>
<h3>Hello JSX</h3>
{/* toUpperCaseメソッドで文字列をすべて大文字にします。 */}
<h3>{upperCaseText.toUpperCase()}</h3>
{/* +演算子で文字列を結合します。 */}
<h3>{'Hello ' + title}</h3>
{/* 配列がJSX内で渡されると自動的に要素が展開されて表示されます。 */}
<h3>{array}</h3>
{/* 関数の実行はreturnに続く値が返ってきます。 */}
<h3>{fn('Hello')}</h3>
</>
);
};
export default Example;
props
import Child from "./components/Child";
const Example = () => {
return (
<>
<Child />
<Child color="red" />
</>
)};
// 属性を指定して値を渡すことが可能
export default Example;
import "./Child.css";
// 外部から値を渡して再利用性を
// const Child = (props) => {
// propsである必要なし pでも慣習的に暗黙ルール
// 分割代入する場合
const Child = ({ color:c = 'green' }) => {
// green:初期値設定
// color:c colorの値をcとして置き換えて使う
console.log()
return (
<>
<div className={`component ${c}`}>
<h3>Hello Component</h3>
</div>
</>
);
};
export default Child;
Props2
import Child from "./components/Child";
const Example = () => {
const hello = (arg) => `ello ${arg}`;
const o = {
color: "red",
num:123,
}
return (
<>
{/* <Child /> */}
{/* <Child color="red" /> →エラー*/}
{/* 下記でfnを渡すように定義されていることから、呼び出す際にpropsとして関数を渡していないのでfnはundefinedとなり、fn is not a functionとなる */}
<Child
{...o}
// スプレッド演算子でオブジェクトの値が展開される。
// num={123}
fn={hello}
bool
obj={{ name:'Tom',age:18 }}
// trueの値が渡ってくる
/>
{/* 属性が定義されていない分についてはundefinedとなる。 */}
</>
)
};
// 属性を指定して値を渡すことが可能
export default Example;
/* POINT 式と文
式:何らかの値を返すもの(変数に代入できるもの)
文:変数宣言、for文、if文、switch文やセミコロンで区切るもの。
*/
import "./Child.css";
// 外部から値を渡して再利用性を
// const Child = (props) => {
// propsである必要なし pでも慣習的に暗黙ルール
// 分割代入する場合
// const Child = (props) => {
// console.log(props)
const Child = ({ color:c = 'green',num, fn,bool,obj }) => {
// green:初期値設定
// color:c colorの値をcとして置き換えて使う
console.log();
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;
チルドレン
import Profile from "./components/Profile";
import Container from "./components/Container";
const profile = [
{ name: "Takashi", age: 19, country: "Japan", color: "green" },
{ name: "Jane", age: 28, country: "UK", color: "red" },
];
const Example = () => {
return (
<div>
<Container title="Childrenとは?" >
<Profile {...profile[0]} />
</Container>
</div>
);
};
const Example2 = () => {
return (
<div>
<Container title="Childrenとは?" children={
[<Profile key={profile[0].name} {...profile[0]} />,
<Profile key={profile[1].name} {...profile[1]} />]
} first={<Profile key={profile[0].name} {...profile[0]} />}
second={<Profile key={profile[1].name} {...profile[1]} />}
/>
{/* 上記の表現でも問題なし、このコンポーネント自体もjavascriptのオブジェクトになりますので、この列に格納することができます。 */}
</div>
);
};
export default Example2;
propsのルール
// POINT propsの流れは一方通行 親から子へ
// POINT propsは読み取り専用
import Bye from "./components/Bye"
import Hello from "./components/Hello"
const Example = () => {
const name = "Tom";
return (
<>
<Hello name={ name } />
<Bye name={name } />
</>
);
};
export default Example;
const Hello = (props) => {
// props.name = 'BOb';// エラー読み取り専用props
const desc = Reflect.getOwnPropertyDescriptor(props, 'name');
console.log(desc);
// configurable:false;変更できるか?できない
// writable:false;書き換え可能か?不可
return (
<div>
<h3>Hello {props.name}</h3>
</div>
);
};
export default Hello;
const Bye = (props) => {
const name = 'Tom';
// Helloへは渡せない
// 親コンポーネント
return (
<div>
<h3>Bye {props.name}</h3>
</div>
);
};
export default Bye;
jsxの正体
babelにて関数に置き換えられ、オブジェクトになる。
JSXはJSのオブジェクトに変換される。
JSオブジェクト(React要素)
const sample2 = (
<div>
<h1>Hello!</h1>
<h2>Good to see you.</h2>
</div>
);
Babel変換
const sample2 =React.createElement(
"div",//タグ名
null,// プロップスの値
React.createElement("h1", null, "Hello!"),
React.createElement("h2", null, "Good to see you.")
);
実行結果
const element ={
type:'h1',
props:{
className:'greeting',
children:'Hello World'
}
};
開発で利用するイベントについて
const Example = () => {
const clickHandler = () => {
alert('ボタンがクリックされrました。');
// 戻り値returnがないのでundefinedの戻り値が返ってくる。
}
// 極力名前付き関数を定義してから下記に入力
const hello = () => 'hello react';
console.log(hello)
// () => 'hello react'がそのまま表示される。
console.log(hello());
// hello reactが表示される。
return (
<>
<button onClick={clickHandler}>クリックしてね</button>
{/* onClickのCは大文字 */}
{/* clickHander()(関数を実行したもの)と()をつけるわけではなくclickHandler(ボタンを押されて実行するもの)として記載する。 */}
<button onClick={() => clickHandler()}>クリックしてね</button>
{/* 上記の場合には関数の実効記載が必要。クリックされてから関数が実行するため、実行されたreturnには()を付けないと関数が戻り値となってしまう。 */}
<button>クリックしてね</button>
{hello()}
</>
);
};
export default Example;
import "./Example.css";
const Example = () => {
return (
<div>
<h3>コンソールを確認してください。</h3>
<label>
入力値のイベント:
<input
type="text"
onInput={() => console.log("onChange検知")}
//JSにおけるonInputがReactのonChangeイベントと同じ(変更された時に発火する)ようになる
// 通常JSではonchangeイベントは入力を終えてフォーカスが外れた時に動作する。
onBlur={() => console.log("onBlur検知")}
// 入力欄からフォーカスが消えた時を検知
onFocus={() => console.log("onFocus検知")}
// 入力欄からフォーカスを得た時を検知
/>
</label>
<div>
<label>
入力値を取得:
<input type="text" onChange={(e) => console.log(e.target.value)} />
</label>
</div>
{/* マウスホバー時を検知 */}
<div
className="hover-event"
onInput={() => console.log("カーソルが入ってきました。")}
onChange={() => console.log("カーソルが入ってきました。")}
onMouseEnter={() => console.log("カーソルが入ってきました。")}
onMouseLeave={() => console.log("カーソルが出ていきました。")}
>
ホバーしてね!
</div>
</div>
);
};
export default Example;
useState
import { useState } from "react";
const Example = () => {
let valArry = useState("hello");
let [val, setVal] = useState('hello');
// [0,f]
//配列の0番目に参照用の値が渡ってきます。
// 配列の0番目:参照用の値
// 配列の1番目:更新用の関数
// 初期値0
// 読み込み用と
console.log(valArry)
return (
<>
<input
type="text"
onChange={(e) => {
// const setFn = valArry[1];
setVal(e.target.value)
// 更新されない
}} /> = {val}
</>
);
};
export default Example;
変数の値を変えても画面の表示は変わらない理由
・Reactにコンポーネントの再実行(再レンダリング)を依頼し、新しいReact要素を作成してもらう必要がある。
・変更した値をどこかに保持しておく必要がある。(stateに保存)
これらを可能にする仕組みが useState
import { useState } from "react";
const Example = () => {
let displayVal;
//2. Exampleが実行されるたびに値が空になってしまう。
let [ val, setVal ] = useState();
console.log('再レンダリングされました');
return (
<>
<input
type="text"
onChange={(e) => {
console.log(e.target.value);
setVal(e.target.value);
//1. displayVal = e.target.value; onChangeにおってコードが実行される
}}
/>
= {val}{/* このコードはExample()が実行されないと変わらない/3.さらにExampleが実行されると2の挙動で空が反映される。 */}
</>
);
};
export default Example;
1.接続hook Into
React内部と接続。状態が管理されるようになる。
2現在の値と更新関数を返却
3.更新関数で新しい値をReactに渡す。また、Reactに自身のコンポーネントを再実行するように依頼する。
useStateはコンポーネントごとに保持
import { useState } from "react";
const Example = () => {
let displayVal;
//2. Exampleが実行されるたびに値が空になってしまう。
let [ val, setVal ] = useState();
console.log('再レンダリングされました');
return (
<>
<input
type="text"
onChange={(e) => {
console.log(e.target.value);
setVal(e.target.value);
//1. displayVal = e.target.value; onChangeにおってコードが実行される
}}
/>
= {val}{/* このコードはExample()が実行されないと変わらない/3.さらにExampleが実行されると2の挙動で空が反映される。 */}
</>
);
};
export default Example;
import { useState } from "react";
const Example = () => {
// let displayVal;
//2. Exampleが実行されるたびに値が空になってしまう。
let [ val, setVal ] = useState();
console.log('再レンダリングされました');
return (
<>
<input
type="text"
onChange={(e) => {
console.log(e.target.value);
// displayVal =e.target.value
setVal(e.target.value);
//1. displayVal = e.target.value; onChangeにおってコードが実行される
}}
/>
{/* = {displayVal} */}
{/* Stateを利用しないと再レンダリングされない */}
= {val}
{/* このコードはExample()が実行されないと変わらない/3.さらにExampleが実行されると2の挙動で空が反映される。 */}
</>
);
};
export default Example;```
```jsx
import { useState } from "react";
const Example = () => {
console.log(<Example />)
// _owner FiberNode
// memorizedStateにて値が保持される。
// 次の値はnextに入っている。
const [btnValA, setValA] = useState(0);
// コンポーネントのトップレベルしか呼ぶことができないuseState
// if,for,whileなど{}文内においても使用できない。
// setValAの関数と紐付けされたbtnValAが更新される
const [btnValB, setValB] = useState(10);
// 順番で定義されたもの保持されるuseState
const [ btnValC, setValC ] = useState(100);
const btnCountUp = () => {
setValA(btnValA + 1);
}
const btnCountUpB = () => {
setValB(btnValA + 1);//更新されない
}
const btnCountUpC = () => {
setValC(btnValC + 1);
}
return (
<>
<p>ボタンAを{btnValA}回押しました!</p>
<button onClick={btnCountUp}>ボタンA</button>
<p>ボタンBを{btnValB}回押しました!</p>
<button onClick={btnCountUpB}>ボタンB</button>
<p>ボタンAを{btnValC}回押しました!</p>
<button onClick={btnCountUpC}>ボタンA</button>
</>
);
};
export default Example;
import { useState } from "react";
const Example = () => {
const [count, setCount] = useState(0);
const countUp = () => {
setCount(count + 1);//:値は1//非同期処理となる。
setCount(count + 1);//:値は1
setCount(p => p + 100);//:値は101 関数の引数は前の関数の結果
setCount(p => p + 1);//:値は1
console.log(count);
}
const countDown = () => {
setCount(count - 1);
}
return (<>
<p>現在のカウント数:{count}</p>
<button onClick={(countUp)}>+</button>
<button onClick={(countDown)}>-</button>
</>);
};
export default Example;
useStateの注意点
useStateの関数については予約という考え方のため、
即時処理が行われない。
そのため、関数の実行する際に現在の状況を反映させたい場合には、
set関数内に関数を設置することで値を引用して更新される。
import { useState } from 'react';
const Example = () => {
const [count, setCount] = useState(0);
const countUp = () => {
setCount(state => state + 1);
// 現在の値を見て行う場合が多いので常時上記の使い方で実施
};
const countDown = () => {
setCount(state => state - 1);
};
return (
<>
<h3>練習問題</h3>
<p>現在のカウント数: {count}</p>
<button onClick={countUp}>+</button>
<button onClick={countDown}>-</button>
</>
);
};
export default Example;
オブジェクト型のuseStateの注意点
// POINT プリミティブ型:1, "str", bool, 10n, Symbol(), null, undefined
// POINT オブジェクト型:{}, []などのプリミティブ型以外
// POINT オブジェクト型のstateを変更する場合には必ず新しいオブジェクトを作成する!
import { useState } from "react";
const Example = () => {
const personObj = { name: "Tom", age: 18 };
const [person, setPerson] = useState(personObj);
const changeName = (e) => {
setPerson({ name: e.target.value, age: person.age });
// setPerson({ name: e.target.value, age: person.age });
// ageプロパティを消してしまうと更新されてしまうので、setPersonを実行する際には必ず同じ構造で記載すること。
}
const changeAge = (e) => {
setPerson({ name: person.name, age:e.target.value });
}
const reset = () => {
setPerson({ name: "", age: "" });
}
return (
<>
<h3>Name:{person.name}</h3>
<h3>Age:{person.age}</h3>
<input type="text" name="" onChange={changeName} id="" value={person.name} />
<input type="number" name="" onChange={changeAge} id="" value={person.age} />
<div>
<button onClick={reset}>リセット</button>
</div>
</>
);
};
export default Example;
オブジェクトのuseStateについて
import { useState } from 'react';
const Example = () => {
const orderObj = { item: 'apple', count: 10 };
const [order, setOrder] = useState(orderObj);
const changeItem = (e) => { setOrder({ ...order, item: e.target.value }) };
// スプレッド演算子で展開
const countUp = () => {
setOrder((order) => ({ ...order, count: order.count + 1 }));
// 配列に()をつけるのは配列がオブジェクトリテラルなのか、あろー関数の関数式か不明であるため、オブジェクトを返す場合には()入れる。
};
const countDown = () => {
setOrder((order) => ({ ...order, count: order.count - 1 }));
};
return (
<div>
<h3>練習問題</h3>
<p>
記述を変更し、完成コードのように「+と-ボタンをクリックするとCountの表示が1ずつ増減する機能」と「input要素に連動してItemの表示が変更される機能」を実装してください。コンポーネントの外側(上部)に変数や関数を準備しているためうまく使ってください。
</p>
<h3>Item:{order.item}</h3>
<h3>Count:{order.count}</h3>
<input type="text" value={order.item} onChange={changeItem} />
<button onClick={countUp}>+</button>
<button onClick={countDown}>-</button>
</div>
);
};
export default Example;
配列のuseState
import {useState} from "react"
const Example = () => {
const numArray = [1, 2, 3, 4, 5];
const [nums, setNums] = useState(numArray);
console.log(nums);
const shuffle = () => {
const newNums = [...nums];
// スプレッド演算子として定義する。新しい配列として定義する。
// newNums =numsは配列がコピーではなく、配列の参照をコピーしている。
const value = newNums.pop();
newNums.unshift(value);
setNums(newNums);
// 配列の末尾が削除
console.log(newNums)
}
return (
<>
<h1>{nums}</h1>
{/* {}で展開されると並んで表示される。 */}
<button onClick={shuffle}>shuffle</button>
</>
);
};
export default Example;
State
State はコンポーネント毎に保持
コンポーネントに紐づく値はそれぞれ独立して管理される。
React要素のツリー内の位置によってどのコンポーネントのstateか識別している。
コンポーネントのReact要素ツリーにおける位置が変わらない場合はstateは保持される。
しかし、keyをつけることによって同じ位置の同じコンポーネントでも別物と認識させられる。
import { useState } from "react";
const Example = () => {
const [toggle, setToggle] = useState(true);
const toggleComponent = () => {
setToggle(prev => !prev)
}
return (
<>
<button onClick={toggleComponent}>toggle</button>
{toggle ? <Count title="A" /> : <Count title="B" />}
{/* 上記の内容では表示位置が変わらない */}
{/* stateの値を引き継ぐ、同じ位置で切り替わる場合について */}
{toggle ? <Count title="A" /> : <div><Count title="B" /></div>}
{/* 上記の場合にはdivがBに追加されているためツリー構造が変わることから値が引き継がれない */}
<Count title="A" />
{toggle && <Count title="B" />}
{/* 上記の場合にはコンポーネントが消滅するため、値が初期化される。 */}
{toggle ? <Count key="A" title="A" /> : <Count key="B" title="B" />}
{/* 上記のコンポーネントが値を別々にしたい場合にはkeyという属性を設定することで、一意のコンポーネントの値を管理できる。 */}
</>
)
}
const Count = ({ title }) => {
const [count, setCount] = useState(0);
const countUp = () => {
setCount((prevstate) => prevstate + 1);
};
const countDown = () => {
setCount(count - 1);
};
return (
<>
<h3>{title}: {count}</h3>
<button onClick={countUp}>+</button>
<button onClick={countDown}>-</button>
</>
);
};
export default Example;
stateをpropsで渡すケース
・コンポーネントが消滅する可能性がある時
・特定のstateを複数の子コンポーネントで共有したいとき
import { useState } from "react";
const Example = () => {
const [toggle, setToggle] = useState(true);
const [countA, setCountA] = useState(0);
const [countB, setCountB] = useState(0);
const toggleComponent = () => {
setToggle(prev => !prev);
}
return (
<>
<button onClick={toggleComponent}>toggle</button>
{/* {toggle ? <Count key="A" title="A" count={count} setCount={setCount} /> : <Count key="B" title="B" count={count} setCount={setCount} />} */}
{/* 定義したSTATEをpropsで渡す(値を共有する) */}
<Count key="A" title="A" count={countA} setCount={setCountA} />
<Count key="B" title="B" count={countB} setCount={setCountB} />
</>
)
}
const Count = ({ title,count,setCount }) => {
const countUp = () => {
setCount((prevstate) => prevstate + 1);
};
const countDown = () => {
setCount(count - 1);
};
return (
<>
<h3>{title}: {count}</h3>
<button onClick={countUp}>+</button>
<button onClick={countDown}>-</button>
</>
);
};
export default Example;
useState:値と際レンダリングを依頼
・コンポーネントの中で呼び出す。
・if文やfor文の中で呼び出さない
・値の更新と再レンダリングは予約(非同期される)