Как изменить параметр hook в реагировать (fetch hook) - PullRequest
0 голосов
/ 20 марта 2020

Мой хук извлечения:

  import { useEffect, useState } from "react";

export const useOurApi = (initialUrl, initialData) => {
  const [url, setUrl] = useState(initialUrl);
  const [isLoading, setIsLoading] = useState(true);
  const [hasError, setHasError] = useState(false);
  const [fetchedData, setFetchedData] = useState(initialData);

  useEffect(() => {
    let unmounted = false;

    const handleFetchResponse = response => {
      if (unmounted) return initialData;

      setHasError(!response.ok);
      setIsLoading(false);
      return response.ok && response.json ? response.json() : initialData;
    };

    const fetchData = () => {
      setIsLoading(true);
      return fetch(url, { credentials: 'include' })
        .then(handleFetchResponse)
        .catch(handleFetchResponse);
    };

    if (initialUrl && !unmounted)
      fetchData().then(data => !unmounted && setFetchedData(data));

    return () => {
      unmounted = true;
    };
  }, [url]);

  return { isLoading, hasError, setUrl, data: fetchedData };
};

Я вызываю этот хук в функции следующим образом:

//states
    const [assignments, setAssignments] = useState([])
    const [submissions, setSubmissions] = useState([])
    const [bulk_edit, setBulk_edit]     = useState(false)
    const [ENDPOINT_URL, set_ENDPOINT_URL]  = useState('https://jsonplaceholder.typicode.com/comments?postId=1')

    let url = 'https://jsonplaceholder.typicode.com/comments?postId=1';
    const { data, isLoading, hasError } = useOurApi(ENDPOINT_URL, []); 

Мой вопрос заключается в том, как я могу вызвать этот экземпляр userOurAPI с другим URL , Я пытался вызвать его внутри функции, где мне это нужно, но мы не можем вызывать хуки внутри функций, поэтому я не уверен, как передать ему новый URL для получения новых данных. Я не хочу иметь много экземпляров userOurAPI, потому что это не DRY. Или это невозможно? Впервые на крючки, так что go легко на меня!

Ответы [ 3 ]

0 голосов
/ 20 марта 2020

Чтобы изменить URL-адрес таким образом, чтобы компонент обновлял и выбирал новые данные, вы создаете функцию set, которая изменяет URL-адрес, и вы гарантируете, что useEffect () запускается снова при изменении URL-адреса. Верните функцию установки для URL, чтобы вы могли использовать ее вне первого экземпляра вашей ловушки. В моем коде вы увидите, что я возвращаю setUrl, я могу использовать это для обновления fetch! Глупости с моей стороны не замечать, но, надеюсь, это кому-нибудь поможет.

0 голосов
/ 20 марта 2020

Вы можете сделать это так, как вы выбрали, но есть и другие способы решения этой проблемы.

Другим способом будет всегда повторная загрузка всякий раз, когда URL-адрес изменения, без явного сеттера, возвращенного из ловушки. Это будет выглядеть примерно так:

export const useOurApi = (url, initialData) => { // URL passed directly through removes the need for a specific internal url `useState`
  // const [url, setUrl] = useState(initialUrl); // No longer used

  // ...

  useEffect(() => {
    // Handle fetch
  }, [url]);

  return { isLoading, hasError, data: fetchedData }; // No more `setUrl`
};

Это может не всегда быть тем, что вы хотите, хотя иногда вам может не потребоваться повторно получать все данные при каждом изменении URL, например, если URL пуст , вы можете не захотеть обновлять URL. В этом случае вы можете просто добавить useEffect в пользовательский хук useOurApi, чтобы обновить внутренний URL-адрес и повторить выборку:

export const useOurApi = (initialUrl, initialData) => {
  const [url, setUrl] = useState(initialUrl);

  // ...

  useEffect(() => {
    // Handle fetch
  }, [url]);

  useEffect(() => {
    // ... do some permutation to the URL or validate it
    setUrl(initialUrl);
  }, [initialUrl]);

  return { isLoading, hasError, data: fetchedData }; // No more `setUrl`
};

Если вам все еще иногда требуется повторно получить данные, не связанные на URL, вы можете вывести некоторую функцию из ловушки, чтобы вызвать выборку данных. Примерно так:

export const useOurApi = (initialUrl, initialData) => {
  const [url, setUrl] = useState(initialUrl);
  const [isLoading, setIsLoading] = useState(true);
  const [hasError, setHasError] = useState(false);
  const [fetchedData, setFetchedData] = useState(initialData);

  const refetch = useCallback(() => {
    // Your fetch logic
  }, [url]);

  useEffect(() => {
    refetch(); // In case you still want to automatically refetch the data on url change
  }, [url]);

  return { isLoading, hasError, refetch, data: fetchedData };
};

Теперь вы можете звонить refetch всякий раз, когда хотите запустить повторное извлечение. Возможно, вы все еще захотите изменить внутреннюю ссылку, но это даст вам еще один более гибкий доступ к извлечению и когда это происходит.

0 голосов
/ 20 марта 2020

Вы путаете разницу между простой функцией и функциональным компонентом Функциональным компонентом - не просто простая функция. Это означает, что вы должны вернуть компонент или тег html

Я думаю, вы должны превратить четыре функции в простую функцию, например

export const useOurApi = (initialUrl, initialData) => {
    let url = initialUrl, fetchedData = initialData, 
        isLoading= true, hasError = false, unmounted = false;

    const handleFetchResponse = response => {
        if (unmounted) return initialData;

        hasError = !response.ok;
        isLoading = false;
        return response.ok && response.json ? response.json() : initialData;
    };

    const fetchData = () => {
        isLoading = true;
        return fetch(url, { credentials: 'include' })
            .then(handleFetchResponse)
            .catch(handleFetchResponse);
    };

    if (initialUrl && !unmounted)
        fetchData().then(data => {
            if(!unmounted) fetchedData =data;
            unmounted = true;
        });

    return { isLoading, hasError, url, data: fetchedData };
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...