Бесконечный refre sh в процессе авторизации с реагирующими хуками - PullRequest
1 голос
/ 21 апреля 2020

Я хотел бы реализовать процесс аутентификации с помощью React и React Router, который вызывает API для обновления токена sh при каждом изменении маршрута, но встречается бесконечный refre sh.

const location = useLocation(); // react-router

const [auth, setAuth] = useState({ accessToken: 'aaa', refreshToken: 'bbb' }); // token-based auth

const refresh = useCallback(async () => {
  const response = await fetch(url, auth.accessToken, auth.refreshToken); // pseudo code
  const body = await response.json();
  setAuth({ accessToken: body.accessToken, refreshToken: body.refreshToken });
}, [auth, setAuth]);

useEffect(() => {
  Promise.resolve().then(refresh);
}, [location.pathname, refresh]);

При изменении маршрута (location.pathname) вызывается

useEffect (в зависимости от location.pathname),

auth обновляется (через setAuth),

refresh обновляется (в зависимости от auth),

useEffect вызывается снова (в зависимости от refresh), и затем это продолжается и продолжается.

Рекурсивные зависимости между auth и refresh вызывают это бесконечное l oop. Как это можно решить?

Ответы [ 4 ]

1 голос
/ 21 апреля 2020

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

const refresh = useCallback(() => {
  setAuth((auth) => {
    fetch(url, auth.accessToken, auth.refreshToken)
      .then((res) => res.json())
      .then((body) =>
        setAuth({
          accessToken: body.accessToken,
          refreshToken: body.refreshToken,
        })
      );
    return auth;
  });
}, []);//no dependencies
0 голосов
/ 23 апреля 2020

Вставьте мой окончательный код для справки на основе ответа HMR, спасибо.

const fetchAuth = useCallback(async ({ accessToken, refreshToken }) => {
  const resp = await fetch(...);
  const body = await resp.json();
  return {
    accessToken: body.accessToken,
    refreshToken: body.refreshToken,
  };
}, []);

const onRouteChange = useCallback(async () => {
  setAuth((auth) => {
    setTimeout(async () => {
      const accessToken = auth.accessToken;
      const refreshToken = auth.refreshToken;
      const newAuth = await fetchAuth({ accessToken, refreshToken });
      setAuth(newAuth);
    }, 100);
    return auth;
  });
}, [fetchAuth]);

useEffect(() => {
  onRouteChange();
}, [location.pathname, onRouteChange]);
0 голосов
/ 21 апреля 2020

Все, что вы помещаете в зависимости, заставляет компонент обновлять sh при изменении. В основном ваш обратный вызов обновлял аутентификацию каждый раз, когда аутентификация была новой. И здесь вы видите l oop!

Кстати. вам не нужно указывать setAuth как deps, потому что это константа, которая никогда не меняется!

const refresh = useCallback(async () => {
  setAuth((auth)=>{
  const response = await fetch(url, auth.accessToken, auth.refreshToken); // pseudo code
  const body = await response.json();
    return { accessToken: body.accessToken, refreshToken: body.refreshToken }
  }
}, []);
0 голосов
/ 21 апреля 2020

С тех пор:

  • refresh при выполнении функции изменяется значение auth.
  • Другой auth триггер refresh выполнение функции снова.
  • Запускает процесс снова

Для меня передача refre sh в основную useEffect не имеет смысла

useEffect(() => {
  // Promise.resolve().then(refresh); // This Promise is useful. Just call the function
  refresh()
}, [location.pathname]); // remove refresh from here

Ваша refresh функция в любом случае не имеет смысла. Не следует использовать начальные значения auth состояния.

...