副作用(side effect)とは、JSXを返却する処理およびその状態やイベントハンドラの定義以外の処理
非同期通信など
– DOMの存在を前提とした処理
– stateの更新
– 副作用はuseEffectの中で実行される必要がある
L 状態の更新により再レンダリングが発生するので、無限ループを避けるため、適切な場所で行う必要がある
function Component(){ React.useEffect(()=>{ someSideEffects(); }, []) }
useEffectはレンダリングが完了した後に実行される
function Component(){ React.useEffect(()=>{ new ExternalLibrary('.target-class'); }, []); return ( // jsx... ); }
状態の更新に関しても無限ループが発生しないようにする
function Component(){ const[val, setVal] = React.useState(0); React.useEffect(() =>{ setVal(123); }, []); }
useEffect()はレンダリングが開始された直後に実行される
第二引数の配列を省略すると、コールバックはレンダリング後に毎回実行される
React.useEffect(() =>{ document.title = 'Hello world'; }, []);
function Component(){ const[val, setVal] = React.useState(0); React.useEffect(() =>{ document.title = `Hello. ${firstName} ${lastName}`; }, [firstName, lastName]); }
function App(){ const[num, setNum] = React.useState(0); const handleClick = () => setNum(num + 1); return ( <> <button onClick={handleClick}>{num}</button> {num % 2 === 0 && <Children />} </> ); } function Children(){ React.useEffect(() =>{ console.log('hello'); return() => console.log('bye'); }, []); return <p>I am a child.</p>; }
### 非同期処理
function User({userId}){ const [user, setUser] = React.useState(null); React.useEffect(() => { fetch('/api/users/${userId}') .then(res => res.json()) .then(json => setUser(json)); }, [userId]); return user ? <h1>Hello, {user.name}</h1> : <p>Loading...</p> }
thenの代わりに async/await構文を用いる場合は注意が必要
– DOM操作の例
function ImageSlider({id, images}){ const [swiper, setSwiper] = React.useState(null); React.useEffect(() => { const instance = new Swiper('#${id}', { // options... }); setSwiper(instance); }, [id]); React.useEffect(() => { swiper.update(); }, [images]); return ( <div id={id} className="swiper-container"> <div className="swiper-wrapper"> {images.map(image => ( <div key={image.id} className="swiper-slide"> <img src={image.url} alt={image.title} /> </div> ))} </div> </div> ); }
非同期処理の場合は、TimeIntervalで実装できるのだろうか。。。
何か道が遠いな。