3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

useState更新タイミング/useEffect初回レンダリング、非同期処理

Posted at

たぶん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>;
};

初回レンダリングでフラグをたたせて、二回目以降は条件分岐してやればいい

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?