I
I
Ivan Ivanovich2021-05-04 11:00:44
React
Ivan Ivanovich, 2021-05-04 11:00:44

Why does the hook not work correctly?

Good day.

There are 2 hooks:

useSessionStorage

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

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

  return [value, setValue];
};


and 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];
};


Form page:

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


Accordingly, the handler weighs on the input, which sets the value through setToken .

The problem is that when the useFetch hook is called, the value of the token remains the same.

For example:

The user has entered the page, the value in the form is an empty string.
The user entered data, the value in sessionStorage changed to "somedata", but in the useFetch hook the value is still the old one, i.e. empty line. Even if you directly get the value through sessionStorage.getItem('token') - an empty string. But at the same time, the value in sessionStorage is set correctly, I checked it in useEffect.

Call order:
useFetch (old value) => useEffect in useSessionStorage. Why is another useFetch render not happening, I can’t understand

I can assume that I'm missing an important thing to do here, but I can't figure out what it is yet. Tell me please, what could be the problem?

UPD

Changed useEffect in useSessionStorage

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


Now if you get  sessionStorage.getItem('token') directly in useFetch , everything will be ok, but through the value from the hook, the old value is still the same.

Call order became: useFetch => useSessionStorage => useFetch

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question