应该将使用状态值的拦截器配置的Axios实例存储在状态、ref或useMemo中?

huangapple go评论64阅读模式
英文:

Should I store a Axios instance configured with interceptors that use a state value in a state or ref or useMemo?

问题

https://stackoverflow.com/questions/47167097/should-we-use-axios-inside-both-components-and-store 类似。

我有一个名为 authorization 的状态,其中包含将在 Axios 调用中使用的 Bearer token 值。该状态在上下文中可用,并可使用 useContext 钩子访问。

我创建了 AxiosInstance,其中添加了 interceptors.request.use 以添加 Authorization 头。

到目前为止,我所做的是使用 useMemo,其中 authorization 值作为依赖项。但由于 Axios 操作是异步的,似乎可能会得到错误的 axios 实例。

我进行了一些重构,使用了 useRef,但仍然遇到了一些问题。

然后我实现了观察者模式,并向提供 Axios 客户端的组件发送通知,说明授权标头已更改并更新引用。然而,仍然存在一些情况会调用旧的客户端。

我想知道的是,我应该将其存储在 useState 中,还是在存储 Axios 客户端的方法上存在根本性问题,而我应该忍受这一点,为每个请求创建一个新的 axios 客户端,该客户端获取当前状态中的授权标头。

英文:

Similiar to https://stackoverflow.com/questions/47167097/should-we-use-axios-inside-both-components-and-store

I have a state called authorization which contains the Bearer token value that would be used in Axios calls. The state is available in a context and accessible using the useContext hook.

I create the AxiosInstance where I add a interceptors.request.use to add the Authorization header.

What I've done so far was useMemo with the authorization value a a dependency. But since Axios operation is asynchronous it seems that I may get the wrong axios instance.

I did a bit of refactoring using useRef and I still had a bit of an issue.

What I then did was implement the Observer pattern and send a notification to the component that provides the Axios client that the authorization header was changed and update the ref. However, again there's still some cases where the old client is being invoked.

What I am wondering is should I store it in useState or is there a fundamental problem with the approach of storing the Axios client and instead should I just bite the bullet and create a new axios client per request which takes the authorization header that's presently in the state?

答案1

得分: 1

我通常的做法是将认证信息保存在React上下文或redux中,并根据需要创建axios实例来访问授权令牌。

也许是这样的:

const getBearerToken = () => { ... [从上下文检索的实现在这里] ... };

const webserviceRequest = (url) => () => axios.create({
    baseURL: url,
    ... [AxiosRequestConfig选项在这里] ...
    headers: {
        Authorization: `Bearer ${getBearerToken()}`,
        ...
    },
});

然后您可以通过调用此函数来定义您的网络服务请求例如

```jsx
const sampleGetRequest = () => webserviceRequest(SAMPLE_URL)().get('');
const samplePostRequest = (postData) => webserviceRequest(SAMPLE_URL)().post('', postData);

这些返回一个Promise<AxiosResponse>,您可以像正常调用一样调用它,例如:

sampleGetRequest().then((response) => { ... }).catch((error) => { ... })

等等。

关键点是webserviceRequest返回一个函数,该函数使用当前授权令牌创建异步网络服务请求。您永远不保存webserviceRequest函数,因为该授权令牌可能会变得过时。

英文:

The way I typically do it is to save the authentication information in a React context or to redux, and create axios instances as needed to access the authorization token.

Maybe something like:

const getBearerToken() =&gt; { ... [your implementation to retrieve from context here] ... };

const webserviceRequest = (url) =&gt; () =&gt; axios.create({
    baseURL: url,
    ... [AxiosRequestConfig options here] ...
    headers: {
         Authorization: `Bearer ${getBearerToken()}`, 
         ...
    },
});

Then, you can define your webservice requests by invoking this function, e.g.:

const sampleGetRequest = () =&gt; webserviceRequest(SAMPLE_URL)().get(&#39;&#39;);
const samplePostRequest = (postData) =&gt; webserviceRequest(SAMPLE_URL)().post(&#39;&#39;, postData);

These return a Promise&lt;AxiosResponse&gt; which you can call as normal, e.g.

sampleGetRequest().then((response) =&gt; { ... }).catch((error) =&gt; { ... })

and so on.

The key point is that the webserviceRequest returns a function which creates an asynchronous webservice request with the current authorization token. You don't ever save the webserviceRequest function because that authorization token can become stale.

答案2

得分: 1

使用React上下文的依赖,我会避免使用拦截器来处理这个问题(我会避免完全使用Axios,但这只是我的个人意见)。

相反,尝试创建一个自定义钩子

import axios from "axios";
import { useContext } from "react";

const api = axios.create({ /* 基础URL等 */ });

const useApi = () => {
  const authorization = useContext(AuthContext); // 猜测

  if (authorization) {
    api.defaults.headers.common.Authorization = `Bearer ${authorization}`;
  } else {
    delete api.defaults.headers.common.Authorization;
  }

  return api;
};
英文:

With the dependency on React context, I'd avoid using interceptors for this (I'd avoid using Axios all together but that's just my opinion).

Instead, try creating a custom hook

import axios from &quot;axios&quot;;
import { useContext } from &quot;react&quot;;

const api = axios.create({ /* baseURL, etc */ });

const useApi = () =&gt; {
  const authorization = useContext(AuthContext); // guessing

  if (authorization) {
    api.defaults.headers.common.Authorization = `Bearer ${authorization}`;
  } else {
    delete api.defaults.headers.common.Authorization;
  }

  return api;
};

huangapple
  • 本文由 发表于 2023年2月7日 05:13:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/75366640.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定