Запрос API не получает токен доступа после обновления страницы в React

Я делаю приложение React, используя API Pet-finder. Я храню свой токен доступа внутри контекста. Когда я отображаю конкретную страницу с животными, она отображается нормально (в большинстве случаев, если предположить, что из-за той же проблемы), но когда я обновляю страницу, она выдает ошибку axios с status: 401, для которой в документах API указано Access was denied due to invalid credentials. Когда я проверяю заголовки, он содержит Authorization: "undefined undefined", где должен быть тип токена и сам токен.

Частичное исправление, которое я нашел, заключается в добавлении token к массиву зависимостей useEffect, который я использую для выполнения запроса, но ошибка по-прежнему появляется в консоли при обновлении, и данные загружаются сразу после этого. Кроме того, это единственная страница, на которой я делаю запрос сразу после рендеринга (возможно, это как-то связано с проблемой).

TokenContext.jsx

const TokenContext = createContext();

export const TokenProvider = ({ children }) => {
  const [token, setToken] = useState({});
  let location = useLocation();

  const fetchToken = async () => {
    await axios
      .get("http://localhost:3001/fetchToken")
      .then((res) => {
        const newToken = {
          token: res.data.access_token,
          tokenType: res.data.token_type,
          expires: new Date().getTime() + res.data.expires_in * 1000,
        };

        localStorage.setItem("token", JSON.stringify(newToken));
      })
      .catch((error) => {
        console.info(error);
      });
  };

  useEffect(() => {
    const foundToken = JSON.parse(localStorage.getItem("token"));

    if (!foundToken || token.expires - new Date().getTime() < 10) {
      fetchToken();
    } else {
      setToken(foundToken);
    }
  }, [location.pathname]);

  return (
    <TokenContext.Provider value = {{ token }}>{children}</TokenContext.Provider>
  );
};

export default TokenContext;

Pet.jsx

const Pet = () => {
  const { id } = useParams();
  const { token } = useContext(TokenContext);
  const [isLoading, setIsLoading] = useState(false);
  const [pet, setPet] = useState({});

  useEffect(() => {
    setIsLoading(true);

    petFinderApi
      .get(`/animals/${id}`, {
        headers: {
          Authorization: `${token.tokenType} ${token.token}`,
        },
      })
      .then((res) => {
        setPet(res.data.animal);
        setIsLoading(false);
      })
      .catch((error) => {
        console.info(error);
      });
  }, [token]);

  if (!pet) {
    return (
      isLoading ?? (
        //Spinner renders here
      )
    );
  } else {
    return (
//Stuff will render here
)
  }
};

export default Pet;

При обновлении контекста страницы данные будут потеряны, потому что они не хранятся в каком-либо хранилище постоянно. Вы можете хранить свой токен в памяти браузера (локальное хранилище или куки)

MohdFaizan_06 12.12.2022 18:56
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
1
75
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Токен изначально является пустым объектом:

const [token, setToken] = useState({});

Пока вы извлекаете токен в фоновом режиме, значение токена передается в TokenContext:

<TokenContext.Provider value = {{ token }}>{children}</TokenContext.Provider>

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

useEffect(() => {
// ...
}, [token]); // {}

Попробуйте добавить проверку, чтобы увидеть, является ли токен неопределенным/пустым объектом в useEffect?

  useEffect(() => {
    setIsLoading(true);
    
    if (token && Object.keys(token).length !== 0){
       // grab a pet
    }
  }, [token]);

Вместо того, чтобы писать

  if (!pet) {
    return (
      isLoading ?? (
        //Spinner renders here
      )
    );

Вы также можете использовать React.Suspense для отображения счетчика.

например

import { Suspense } from 'react';

//... other code

return (
   <Suspense fallback = {<MySpinner />}>
      <MyComponentToDisplayWhenPetIsFetched pet = {pet} />
   </Suspense>
);

Этот урок объясняет Саспенс довольно хорошо

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