IwanQ
@IwanQ
Плохие времена часто дают прекрасные возможности

Почему некорректно работает хук?

Доброго времени суток.

Есть 2 хука:

useSessionStorage

const useLocalStorage = (key, initialValue = '') => {
  const [value, setValue] = useState(() => {
    return sessionStorage.getItem(key) || initialValue;
  });

  useEffect(() => {
    sessionStorage.setItem(key, value);
  }, [key, value]);

  return [value, setValue];
};


И useFetch

const useFetch = (url) => {
  const baseUrl = 'http://localhost:3000';
  const [isFetchLoading, setIsFetchLoading] = useState(false);
  const [response, setResponse] = useState(null);
  const [error, setError] = useState(null);
  const [options, setOptions] = useState({});
  const [token] = useSessionStorage('token');

  const doFetch = useCallback(
    (options = {}) => {
      if (!options.method) {
        options.method = 'GET';
      }

      options.headers = {
        ...options.headers,
        'Authorization': token ? `Bearer ${token}` : '',
      };

      if (options.body) {
        options.headers = {
          'Content-Type': 'application/json',
          ...options.headers,
        };
      }

      if (options.body) {
        options.body = JSON.stringify(options.body);
      }

      setOptions(options);
      setIsFetchLoading(true);
    },
    [token]
  );

  useEffect(() => {
    let stopGettingResponseAfterDestroy = false;
    if (!isFetchLoading) return;

    fetch(`${baseUrl}${url}`, options)
      .then((res) => res.json())
      .then((data) => {
        if (!stopGettingResponseAfterDestroy) {
          data.errors ? setError(data) : setResponse(data);
        }
      })
      .catch((err) => {
        if (!stopGettingResponseAfterDestroy) {
          setError(err);
        }
      })
      .finally(() => {
        if (!stopGettingResponseAfterDestroy) {
          setIsFetchLoading(false);
        }
      });

    return () => {
      stopGettingResponseAfterDestroy = true;
    };
  }, [url, isFetchLoading, options]);

  return [{ isFetchLoading, response, error }, doFetch];
};


Страница с формой:

...
  const [token, setToken] = useSessionStorage('token');
  const [{ isFetchLoading, response, error }, doFetch] = useFetch('/login');
...


Соответственно на input весит обработчик, который через setToken устанавливает значение.

Проблема в том, что при вызове хука useFetch, значение токена остается старым.

Например:

Пользователь зашел на страницу, значение в форме пустая строка.
Пользователь ввел данные, значение в sessionStorage изменилось на "somedata", но в хуке useFetch значение все равно старое, т.е. пустая строка. Даже если на прямую получить значение через sessionStorage.getItem('token')- пустая строка. Но при этом значение в sessionStorage устанавливается корректно, в useEffect я это проверил.

Порядок вызовов:
useFetch (старое значение) => useEffect в useSessionStorage. Почему не происходит еще один рендер useFetch, понять не могу

Могу предположить, что я упускаю важную делать здесь, но пока не могу понять что именно. Подскажите пожалуйста, в чем может быть проблема?

UPD

Поменял useEffect в useSessionStorage

useEffect(() => {
    console.log('token useEffect setting value', value);
    sessionStorage.setItem(key, value);
    setValue(value);
  }, [key, value]);


Теперь если в useFetch получать на прямую sessionStorage.getItem('token'), все будет ок, но через значение из хука все равно старое значение.

Порядок вызовов стал: useFetch => useSessionStorage => useFetch
  • Вопрос задан
  • 104 просмотра
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы