Реагируйте на ловушку, чтобы дождаться завершения предыдущего вызова - PullRequest
1 голос
/ 20 июня 2019

Я работаю над реактивным проектом, который использует хуки.И мне была назначена задача

"изменить хук useInterval или создать новый (usePoll?). Это должно работать так же, как useInterval, но должно подождать, пока запрос ajax не будетзавершить до запуска таймера ".

Я новичок в реакции крючков и искал решение для этого, но не смог найти.Текущая функция useInterval выглядит следующим образом.

import React, { useEffect, useRef } from 'react';

export function useInterval(callback, delay, immediate = true) {
    const savedCallback = useRef();

    // Remember the latest callback.
    useEffect(() => {
        savedCallback.current = callback;
    }, [callback]);

    // Set up the interval.
    useEffect(() => {
        function tick() {
            savedCallback.current();
        }
        if (delay !== null) {
            if (immediate) {
                tick();
            }

            let id = setInterval(tick, delay);
            return () => clearInterval(id);
        }
    }, [delay]);
}

и используется в программе следующим образом.

useInterval(() => {
        get(`/api/v1/streams/1`).then(({ data: { data } }) => {
            setStream(data);
        });
    }, 5000);

, и мне нужно изменить функцию useInterval, чтобы дождаться запроса ajaxзавершено до запуска таймера.Было бы здорово, если бы кто-нибудь мог мне помочь в этом.Спасибо

Ответы [ 2 ]

0 голосов
/ 20 июня 2019

Вы можете использовать async\await для ожидания первого вызова.

Изменить внутреннюю useEffect, как это

export function useInterval(callback, delay, immediate = true) {
    const savedCallback = useRef();

    // Remember the latest callback.
    useEffect(() => {
        savedCallback.current = callback;
    }, [callback]);
    // Set up the interval.
    useEffect(() => {
        // useEffect doesn't like async callbacks (https://github.com/facebook/react/issues/14326) so create nested async callback
        (async () => { 
            // Make tick() async
            async function tick() {
                await savedCallback.current();
            }
            if (delay !== null) {
                if (immediate) {
                    await tick();  // Here we should await for tick()
                }

                let id = setInterval(tick, delay);  // Unfortunately setInterval is not async/await compatible. So it will not await for tick
                return () => clearInterval(id);
           }
        })(); // Call nested async function
    }, [delay]);

}

И ваш обратный вызов должен вернуть Promise, чтобы async\await работал правильно

useInterval(() => {
    // After .then promise will be resolved, so our useInterval will know about that
    return get(`/api/v1/streams/1`).then(({ data: { data } }) => {
        setStream(data);
    });
}, 5000);
0 голосов
/ 20 июня 2019

Дайте этому шанс ... он требует вызова функции next внутри then, но он должен приближаться к тому, что вы ищете.

function useInterval(handler, delay, immediate = true) {
  React.useEffect(() => {
    let interval

    const start = () => {
      clearInterval(interval)
      interval = setInterval(() => handler(start), delay)
    }

    handler(start)

    return () => clearInterval(interval)
  }, [])
}

использование:

useInterval((next) => {
    get('/api/v1/streams/1').then(data => {
        // tell the timer to begin
        next()
    })
}, 5000)
...