画面が変更されるためには
- 再レンダリング(コンポーネントの再実行)
- 変更した値をstateに保存
を行う必要がある。
let displayVal;
return (
<>
<input
type = "text"
onChange = {(e) =>{
displayVal = e.target.value
}}/> = {displauyVal}
</>
);
};
export default Example;
このように書いても値の更新は行われない
そこで使用するのが、 「useState」である。
目次
useStateの役割と使い方
const[現在の値, 更新関数] = 初期値
const[val, setVal] = useState(0)
//値を更新したい場合は、更新関数を用いる
setVal(1)
使用例(これはExampleそのものが再実行される)
import { useState } from 'react';
const Example = () => {
let [val, setVal] = useState();
console.log("再レンダリングされたよ")
return (
<>
<input
type = "text"
onChange = {(e) =>{
console.log(e.target.value);
setVal(e.target.value);
}}
/>
={val}
</>
);
};
export default Example;
useStateを使用するときの注意点
useStateの呼び出しは必ずトップレベルで(if文の中などでない)呼び出す必要がある。
以下を実行し、consoleを確認してみると、
import {useState} from "react"
const Example = () =>{
console.log(<Example/>);
const[ countA, setCountA] = useState(0);
const[ countB, setCountB] = useState(10);
const[ countC, setCountC] = useState(100);
return(
<>
<p>ボタンAを{countA}回押しました!</p>
<button onClick = {() =>{
setCountA(countA + 1);
}}>ボタンA</button>
<p>ボタンAを{countB}回押しました!</p>
<button onClick = {() =>{
setCountB(countB + 1);
}}>ボタンB</button>
<p>ボタンAを{countC}回押しました!</p>
<button onClick = {() =>{
setCountC(countC + 1);
}}>ボタンC</button>
</>
)
}
memoizedStateのnextに値が保持されていることがわかる。if文やloop文などを用いてuseStateの実行順序が変わるので、エラーとなってしまう。
stateはコンポーネント毎に状態(値)を保持する
コンポーネントに紐づく値はそれぞれ独立して管理される
React要素のツリー内の位置によってどこのコンポーネントのstateか識別している。
以下の例では、countAとcountBを別々の値としてコンポーネントが保持しているので、togleの切り替えをしても値は保持される。
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 = {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;
配列のリスト表示
const animals = ["Dog", "Cat", "Rat"];
const Example = () => {
//animalsの要素をanimalとして受け取る
const helloAnimals = animals.map((animal) => <li>hello,{animal}</li>)
return (
<>
<h3>配列の操作</h3>
<ul>
{/* {helloAnimals} */}
{/* for文はjsxに記述できないが、mapならできるので、Reactではしばしばこちらを使用する */}
{animals.map((animal) => <li key = {animal}>hello,{animal}</li>)}
</ul>
</>
);
};
export default Example;
keyは一意に定まるものをつける。このkeyがあることでReactが再レンダリングの差分比較を行い、変更がある箇所のみを更新(commit)できる。
レンダリング前
- key = “js”
- key = “ruby”
- key = “Java”
再レンダリング後
- key = “ruby”
- key = “python”
- key = “Go”
- key = “Java”
差分比較の結果key=”Go”のcommitを行う。
条件分岐
import { useState } from "react";
const Example = () => {
const animals = ["Dog", "Cat", "Rat"];
const [filterVal, setFilterVal] = useState("");
return (
<>
<input
type="text"
value={filterVal}
onChange={(e) => setFilterVal(e.target.value)}
/>
<ul>
{animals
.filter((animal) => {
const isMatch = animal.indexOf(filterVal) !== -1;
console.log(animal.indexOf(filterVal));
return isMatch;
})
.map((animal) => {
//if文ver
if(animal == "Dog"){
return (<li key={animal}>{animal + "★"}</li>)
} else{
return (<li key={animal}>{animal}</li>)
}
})
}
</ul>
</>
);
};
export default Example;
三項演算子ver
//三項演算子ver
return <li key ={animal}>{
animal + (animal =="Dog" ? "★" : "")
}</li>
Reactでは真偽値は表示されないことを利用すると、すっきり記述できる
animal == “Dog”
がfalse
になると表示されない
return(<li>{animal}{animal == "Dog" && "★"}</li>)
その他には、NULL合体演算子というのもある。
A ?? B
Aがnullかundefinedの時にはBの値をとりそれ以外ならAの値を取る。