Пользовательский хук useAxios в реакции

Я использую axios с реакцией, поэтому я решил написать собственный хук для этого, что я и сделал, и он отлично работает, как показано ниже.

  const useAxios = () => {
  const [response, setResponse] = useState([]);
  const [error, setError] = useState("");
  const [loading, setLoading] = useState(true); //different!
  const [controller, setController] = useState();

  const axiosFetch = async (configObj) => {
    const { axiosInstance, method, url, requestConfig = {} } = configObj;

    try {
      const ctrl = new AbortController();
      setController(ctrl);
      const res = await axiosInstance[method.toLowerCase()](url, {
        ...requestConfig,
      });

      setResponse(res.data);
    } catch (err) {
      console.info(err.message);
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    console.info(controller);

    // useEffect cleanup function
    return () => controller && controller.abort();
  }, [controller]);

  return [response, error, loading, axiosFetch];
};

Я также создал один axiosInstance для передачи BASE_URL и заголовков. Теперь вызываем useAxios для получения данных из API, как показано ниже.

  const [data, error, loading, axiosFetch] = useAxios();
  const getData = () => {
    axiosFetch({
      axiosInstance: axios,
      method: "GET",
      url: "/url",
    });
  };
  useEffect(() => {
    getData();
  }, []);

Мой вопрос

  • Когда мне нужно вызвать один API, я делаю выше.
  • Но что, если мне нужно вызвать три или четыре API на одной странице.
  • Должен ли я воспроизвести такой код const [data1, error1, loading1, axiosFetch]=useAxios();
  • Или есть другой способ минимизировать код.

Изменить/обновить

Я запустил приведенный выше код, чтобы получить данные из /url, что, если я хочу нажать другой route, чтобы получить еще одни данные с сервера для другой работы, базовый URL-адрес останется прежним.

Итак, если второй маршрут /users

  const [data, error, loading, axiosFetch] = useAxios();
  const getUsers = () => {
    axiosFetch({
      axiosInstance: axios,
      method: "GET",
      url: "/users",
    });
  };
  useEffect(() => {
    getUsers();
  }, [on_BTN_Click]);

Приведенный выше код я хочу запустить в одном файле, один для получения данных и один для пользователей, как мне написать свои аксиомы, так как я думаю, что это const [data, error, loading, axiosFetch] = useAxios(); должно вызываться только один раз, не знаю, как это сделать или что такое правильно, нужно ли мне менять крючок useAxios?

Вам нужно будет написать один хук на запрос. По крайней мере, это образец.

Slava Knyazev 10.01.2023 17:49
Создание микрофронтендов с Angular и федерацией модулей в монорепо: Пошаговое руководство
Создание микрофронтендов с Angular и федерацией модулей в монорепо: Пошаговое руководство
Микрофронтенды стали популярным архитектурным паттерном для веб-разработки. С появлением федерации модулей в Webpack 5 реализация микрофронтендов...
От React к React Native: Руководство для начинающих по разработке мобильных приложений с использованием React
От React к React Native: Руководство для начинающих по разработке мобильных приложений с использованием React
Если вы уже умеете работать с React, создание мобильных приложений для iOS и Android - это новое приключение, в котором вы сможете применить свои...
Революционная веб-разработка ServiceNow
Революционная веб-разработка ServiceNow
В быстро развивающемся мире веб-разработки ServiceNow для достижения успеха крайне важно оставаться на вершине последних тенденций и технологий. По...
Как добавить SEO(Search Engine Optimization) в наше веб-приложение и как это работает?
Как добавить SEO(Search Engine Optimization) в наше веб-приложение и как это работает?
Заголовок веб-страницы играет наиболее важную роль в SEO, он помогает поисковой системе понять, о чем ваш сайт.
Руководство для начинающих по веб-разработке на React.js
Руководство для начинающих по веб-разработке на React.js
Веб-разработка - это захватывающая и постоянно меняющаяся область, которая постоянно развивается благодаря новым технологиям и тенденциям. Одним из...
Разница между Angular и React
Разница между Angular и React
React и AngularJS - это два самых популярных фреймворка для веб-разработки. Оба фреймворка имеют свои уникальные особенности и преимущества, которые...
0
1
80
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Что вы можете сделать, так это передать конечную точку хуку или правильно вызвать обратный вызов axiosFetch с разными конечными точками. Но у меня есть другое мнение о том, что вы пытаетесь сделать, и вот мои 5 центов о том, почему этот «хук аксиос» может быть плохой идеей.

Хорошее эмпирическое правило для React Hooks — использовать собственный хук, если вам нужно инкапсулировать логику компонента, использующую React Hooks.

Еще одна важная вещь, которая описана в документации React Hooks:

Пользовательские хуки — это механизм повторного использования логики с отслеживанием состояния (например, настройка подписки и запоминание текущего значения), но каждый раз, когда вы используете пользовательский хук, все состояние и эффекты внутри него полностью изолированы.

Таким образом, в конечном итоге, если 2 разных компонента вызывают выборку для одной и той же конечной точки, они оба будут выполнять вызов к серверной части. Как это предотвратить? Ну, вы могли бы использовать библиотеку, такую ​​​​как React Query, которая создает для вас своего рода «кеш» (и кучу других приятных функций!)

И последнее, но не менее важное: вызовы API гораздо больше связаны с Service/Module, чем с React Hook (изолировать логику компонента) как концепцию. Я вряд ли советую вам создавать службу для выполнения вызовов API и использования этой службы внутри вашего хука вместо того, чтобы связывать эту логику с вашим хуком и решать всевозможные проблемы, такие как кэширование и несколько экземпляров одного и того же хука или даже несколько экземпляров одного и того же хука. этот хук вызывает несколько разных конечных точек, которые в конечном итоге могут или не могут зависеть сами от себя.

Я не могу использовать ответный запрос по некоторым причинам, не могли бы вы помочь мне с одним примером с этим - I hardly advise you to create a service for making API calls and using that service inside your hook instead of coupling that logic to your hook and having to handle all kinds of issues

manish thakur 10.01.2023 18:17

Вы можете создать службу запросов (абстракцию) для выполнения ваших запросов (вызовы get, post, patch и delete). Затем, поверх этой службы запросов, вы можете создать другую службу для каждого «домена», которая использует вашу службу запросов «под капотом» и выполнять запросы и предоставлять такие функции, как getProducts() или getProduct(productId), createProduct(productObj). При этом вы изолируете логику и максимально отделяете логику вашего приложения от используемых вами библиотек.

Ilê Caian 10.01.2023 19:08

Как насчет общего хука useAsync, который принимает любой асинхронный вызов? Это отделяет специфику аксиом от хука.

function useAsync(func, deps = []) {
  const [state, setState] = useState({ loading: true, error: null, data: null })
  useEffect(
    () => {
      let mounted = true
      func()
        .then(data => mounted && setState({ loading: false, error: null, data }))
        .catch(error => mounted && setState({ loading: false, error, data: null }))
      return () => { mounted = false }
    },
    deps,
  )
  return state
}

Вот основной пример его использования -

function UserProfile({ userId }) {
  const user = useAsync(
    () => axios.get(`/users/${userId}`),  // async call
    [userId],                             // dependencies
  })
  if (user.loading)
    return <Loading />
  if (user.error)
    return <Error message = {user.error.message} />
  return <User user = {user.data} />
}

Идея в том, что можно выполнить любую асинхронную операцию. Более сложный пример может выглядеть так:

function UserProfile({ userId }) {
  const profile = useAsync(
    async () => {
      const user = await axios.get(`/users/${userId}`)
      const friends = await axios.get(`/users/${userId}/friends`)
      const notifications = await axios.get(`/users/${userId}/notifications`)
      return {user, friends, notifications}
    },
    [userId],
  )
  if (profile.loading) return <Loading />
  if (profile.error) return <Error message = {profile.error.message} />
  return <>
    <User user = {profile.data.user} />
    <Friends friends = {profile.data.friends} />
    <Notifications notifications = {profile.data.notifications} />
  </>
}

В последнем примере все выборки должны быть завершены, прежде чем данные смогут начать рендеринг. Вы можете использовать хук useAsync несколько раз, чтобы получить параллельную обработку. Не забывайте, что вам нужно проверить loading и error, прежде чем вы сможете безопасно получить доступ к data -

function UserProfile({ userId }) {
  const user = useAsync(() => axios.get(`/users/${userId}`), [userId])
  const friends = useAsync(() => axios.get(`/users/${userId}/friends`), [userId])
  const notifications = useAsync(() => axios.get(`/users/${userId}/notifications`), [userId])
  return <>
    { user.loading
    ? <Loading />
    : user.error
    ? <Error message = {user.error.message }
    : <User user = {user.data} />
    }
    { friends.loading
    ? <Loading />
    : friends.error
    ? <Error message = {friends.error.message} />
    : <Friends friends = {friends.data} />
    }
    { notifications.loading
    ? <Loading />
    : notifications.error
    ? <Error message = {notifications.error.message} />
    : <Notifications notifications = {notifications.data} />
    }
  </>
}

Я бы порекомендовал вам также отделить аксиомы от ваших компонентов. Вы можете сделать это, написав свой собственный модуль API и даже предоставив крючок useAPI. Посмотрите эти вопросы и ответы, если это покажется вам интересным.

Другие вопросы по теме