たぶんVueからReactに来た人ははまるんじゃないかポイント
useState
初めて見ると変わった書き方だが、ただ状態管理してくれるものconst Qiita = () => {
const [data, setData] = useState(0)
const up = () => {
setData((data) => data + 1)
}
return <div onClick={up}>{data}</div>;
};
クリックしたら1づつ上がる関数である
更新タイミング
ここで私は躓いた 例えば、クリックされプラス1されたとき、この数字をバックエンドに送りたい時なんかを考えるconst Qiita = () => {
const [data, setData] = useState(0)
const up = () => {
setData((data) => data + 1)
console.log(data)
}
return <div onClick={up}>{data}</div>;
};
1回クリックしたときのコンソールは0
2回目は1
おかしいぞ、1ずつずれている
どうやら、useStateのdataが更新されるのはup関数が終了後らしい
それを踏まえて、更新時に何か処理したいときには、こう書けばいいらしい
const Qiita = () => {
const [data, setData] = useState(0)
const up = () => {
setData((data) => data + 1)
}
useEffect(() => {
console.log(data)
//data更新時の処理
}, [data])
return <div onClick={up}>{data}</div>;
};
useEffect
非同期処理
useEffect内で非同期処理をする場合はこうかくconst Qiita = () => {
const [data, setData] = useState(0)
const up = () => {
setData((data) => data + 1)
}
useEffect(() => {
const fetch = async () => {
//非同期処理
await axios.get("API")
}
fetch()
}, [data])
return <div onClick={up}>{data}</div>;
};
これでデータが更新されたときに非同期処理ができる
useEffect(async() => {
await axios.get("API");
},[data])
こう書くとエラーが出てしまう
理由はコールバックの中にasync関数やPromiseはいれられないから
初回レンダリング
useEffectの第二引数に[]を指定するとマウント時にのみレンダリングされる
先ほどのプログラムを例に見てみよう
const Qiita = () => {
const [data, setData] = useState(0)
const up = () => {
setData((data) => data + 1)
}
useEffect(() => {
const fetch = async () => {
console.log("初回レンダリング")
await axios.get("API")
}
fetch()
}, [data])
return <div onClick={up}>{data}</div>;
};
こちら側の意図としてはクリックされてup関数実行され、dataが更新した時にAPIを取得してほしい
だが実際は、dataはマウント時にも更新されるので、クリックする前にgetの処理は一度実行されてしまう
初回レンダリング時のuseEffectの実行を防ぐにはこうかく
const Qiita = () => {
const renderFlgRef = useRef(false);
const [data, setData] = useState(0)
const up = () => {
setData((data) => data + 1)
console.log(data)
}
useEffect(() => {
if (renderFlgRef.current) {
const fetch = async () => {
console.log("クリック時に実行");
//await axios.get("API")
};
fetch();
} else {
renderFlgRef.current = true;
}
}, [data])
return <div onClick={up}>{data}</div>;
};
初回レンダリングでフラグをたたせて、二回目以降は条件分岐してやればいい