ava / use-http

🐶 React hook for making isomorphic http requests
https://use-http.com
MIT License
2.32k stars 114 forks source link

Provider interceptor uses cached values? #135

Closed revolucion closed 4 years ago

revolucion commented 5 years ago

I have created a custom Provider with (global) options to send certain headers on all requests via an interceptor. This interceptor should get a value from a context and send it with the headers, but it doesn't seem to update to the new value.

Created a CodeSandbox here

When you run it and open inspector to check the network calls, you can see that the x-token header remains null on each call, even though the 'token' value is updated in the context as showed in the console and on the component render.

The funny thing is, if I place the exact same interceptor code in the useFetch hook itself, it does send the correct header value. Like so:

    const [request, response] = useFetch({
        interceptors: {
            request: options => {
                console.log("Interceptor called with token", state.token);
                options.headers["x-token"] = state.token;
                return options;
            }
        }
    });
alex-cory commented 5 years ago

Will take a look asap

alex-cory commented 5 years ago

Okay, so we don't typically use onUpdate for something like this. Having onUpdate here would make every http request on your page re-run if the token changed which does not sound like something you want.

We would do it something like

const CustomProvider = ({ children }) => {
  const [token, setToken] = useLocalStorage('token')

  const getToken = async () => {
    return 'my-token'
  }

  const options = {
    interceptors: {
      request: async options => {
        if (!token) {
          const newToken = await getToken()
          setToken(newToken)
        }
        console.log('Interceptor called with token', token)
        options.headers['x-token'] = token
        return options
      },
    },
  }

  useEffect(() => {
    console.log('Logging token', token)
  }, [token])

  return (
    <Provider url={window.location.origin} options={options}>
      {children}
    </Provider>
  )
}

const TestFetch = () => {
  const [token] = useLocalStorage('token')

  const [request, response] = useFetch()

  useEffect(() => {
    async function getSomething() {
      console.log('Performing request with token in context as:', token)
      await request.get('/test.json')
      if (response.ok) console.log('Finished.')
    }
    getSomething()
  }, [])

  return (
    <>
      <span>Token is {token}</span>
    </>
  )
}

const App = () => {
  return (
    <TestProvider>
      <CustomProvider>
        <Snowflakes>
          <Center>
            <TestFetch />
          </Center>
        </Snowflakes>
      </CustomProvider>
    </TestProvider>
  )
}

Does this help at all?

revolucion commented 5 years ago

Thanks for getting back at me!

The onUpdate was something I tried with the idea of "lets see if this works". So that shouldn't have been in the example :) I understand the example that you're giving, however something still seems to not be working. I have updated the example with some clearer code perhaps.

You can see in the console how the CustomProvider logs the state object as it should be when the state changes, however the request is still performed without the updated state values.

Updated example here

Perhaps I'm missing something obvious.

alex-cory commented 4 years ago

Apologies for the delay on this, but I think this PR might fix this. Try v0.2.3. I'm going to close this. If the issue persists, let me know and I will reopen.