Dispatch在放置在Axios拦截器中时无法工作。

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

Dispatch is not working when it is placing in Axios interceptor

问题

我在axios拦截器中使用dispatch事件所以每当我从API得到400错误时我会将事件分派到UI以通知消息和重定向请参考

export const loggerInterceptor = (AXIOS) => {
  const { request, response } = AXIOS.interceptors;
  const token = getCookie(COOKIE_JWT_TOKEN);
  
  request.use((config) => {
    config.performance = calculateTimes();
    config.timestamp = Date.now();
    return config;
  });
  
  response.use(
    (response) => {
      if (response) {
        flightInfo = {
          ...flightInfo,
          ...response.data,
        };
      }
      return Promise.resolve(response);
    },
    (error) => {
      if (error.response.status === 400) {
        addErrorToast();
        window.location.href = window.location.origin + '/app';
      }
      return Promise.reject(error);
    }
  );
};
以下的addErrorToast在我得到400错误时触发正常但是分派没有发生有什么解决方案或建议来解决这个问题吗

const addErrorToast = () => {
  const dispatch = useDispatch();
  dispatch(
    addToast({
      type: "success",
      msg: (
        <FormattedMessage
          id="notifications.connected"
          defaultMessage="You are connected!"
        />
      ),
      hasCloseIcon: false,
    })
  );
};
英文:

I am using dispatch event in axios interceptor, so that whenever i got 400 error from api i will dispatching the event to UI to notify the message and redirection as well.
Please refer

export const loggerInterceptor = (AXIOS ) =&gt; {
      const { request, response } = AXIOS.interceptors;
      const token = getCookie(COOKIE_JWT_TOKEN);
      
      request.use((config) =&gt; {
        config.performance = calculateTimes();
        config.timestamp = Date.now();
        return config;
      });
    
      response.use(
        (response) =&gt; {
          if (
            response
          ) {
            flightInfo = {
              ...flightInfo,
              ...response.data,
            };
          }
          return Promise.resolve(response);
        },
        (error) =&gt; {
         if(error.response.status===400)
          {
            addErrorToast();
           window.location.href= window.location.origin +&#39;/app&#39;;
            
          } 
          return Promise.reject(error);
        }
      );
    };

The below addErrorToast is triggering properly when i get 400 error but dispatch is not happening. Any solutions or suggestions to fix this

const addErrorToast = ()=&gt;{
  const dispatch = useDispatch();
  dispatch(
          addToast({
            type: &quot;success&quot;,
            msg: (
              &lt;FormattedMessage
                id=&quot;notifications.connected&quot;
                defaultMessage=&quot;You are connected!&quot;
              /&gt;
            ),
            hasCloseIcon: false,
          })
      );
}

答案1

得分: 2

你是否在Redux提供程序包装器之外导入此Axios配置?这是一个常见的错误,因为此配置通常会在基本的 index.tsx/main.tsx 文件中导入,而Redux包装器也会在相同文件或 App.tsx 文件中设置,而在这两种情况下,您的Axios配置将无法进行dispatch

确保在Redux提供程序包装器内导入此axios配置。您还希望将此拦截器转换为钩子,以便它可以使用其他钩子。

以下部分无需翻译,因为它们是代码示例。

"WORKING EXAMPLE: React18 + Redux + Axios Interceptor dispatch"

"I created a sandbox with a working example of this situation where an Axios interceptor needs to dispatch to Redux."

接下来是一些代码示例,其中包括 index.jsapp.jsuseAxiosInterceptor.jsstore.jscounterSlice.js 的代码。这些部分无需翻译,因为它们是代码示例。

最后是 package.json 的内容,也无需翻译,因为它是一个JSON配置文件。

希望这些信息对您有所帮助!

英文:

Are you importing this Axios config outside of your Redux Provider wrapper? It's an easy mistake to make since this config would typically be imported in the base index.tsx/main.tsx file and the Redux wrapper set in the same file or App.tsx which in both cases your Axios config will not be able to dispatch.

Make sure you import this axios config within the Redux Provider wrapper. You will also want to turn your interceptor into a hook so it can use other hooks.

This won't work:

index.js

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

import ReactDOM from &#39;react-dom&#39;;
import { BrowserRouter } from &#39;react-router-dom&#39;;
import { Provider } from &#39;react-redux&#39;
import store from &#39;./store&#39;
import App from &#39;./App&#39;;
import initAxios from &#39;./config/axios&#39;;

initAxios(); &lt;--- Not proper hook format (i.e. useXYZ)

ReactDOM.render(
  &lt;BrowserRouter&gt;
    &lt;Provider store={store}&gt;   &lt;--- Store does not wrap Axios
      &lt;App /&gt;
    &lt;/Provider&gt;
  &lt;/BrowserRouter&gt;,
  document.getElementById(&#39;root&#39;),
);

<!-- end snippet -->

WORKING EXAMPLE: React18 + Redux + Axios Interceptor dispatch

I created a sandbox with a working example of this situation where an Axios interceptor needs to dispatch to Redux.

https://codesandbox.io/p/sandbox/react18-axios-interceptor-dispatch-to-redux-jiin13

index.js

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

import { StrictMode } from &quot;react&quot;;
import { createRoot } from &quot;react-dom/client&quot;;
import App from &quot;./App&quot;;
import store from &quot;./store&quot;;
import { Provider } from &quot;react-redux&quot;;

/*
// axios interceptor must be contained within the redux store, App.js
import useAxiosInterceptor from &quot;./useAxiosInterceptor&quot;;

useAxiosInterceptor();
*/

const rootElement = document.getElementById(&quot;root&quot;);
const root = createRoot(rootElement);

root.render(
  &lt;StrictMode&gt;
    {&quot; &quot;}
    {/* &lt;--- 2 renders expected */}
    &lt;Provider store={store}&gt;
      &lt;App /&gt;
    &lt;/Provider&gt;
  &lt;/StrictMode&gt;
);

<!-- end snippet -->

app.js

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

import { useEffect } from &quot;react&quot;;
import { useSelector, useDispatch } from &quot;react-redux&quot;;
import { decrement, increment } from &quot;./counterSlice&quot;;
import axios from &quot;axios&quot;;
import useAxiosInterceptor from &quot;./useAxiosInterceptor&quot;;

export default function App() {
  useAxiosInterceptor();

  const count = useSelector((state) =&gt; state.counter.value);
  const dispatch = useDispatch();

  useEffect(() =&gt; {
    (async () =&gt; {
      try {
        const results = await axios.get(&quot;https://www.google.com&quot;);
        console.log({ results });
      } catch (e) {
        // console.log(e);
      }
    })();
  }, []);

  return (
    &lt;div&gt;
      &lt;div&gt;
        &lt;button
          aria-label=&quot;Increment value&quot;
          onClick={() =&gt; dispatch(increment())}
        &gt;
          Increment
        &lt;/button&gt;
        &lt;span&gt;{count}&lt;/span&gt;
        &lt;button
          aria-label=&quot;Decrement value&quot;
          onClick={() =&gt; dispatch(decrement())}
        &gt;
          Decrement
        &lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
}

<!-- end snippet -->

useAxiosInterceptor.js

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

import axios from &quot;axios&quot;;
import { useDispatch } from &quot;react-redux&quot;;
import { increment } from &quot;./counterSlice&quot;;

const useAxiosInterceptor = () =&gt; {
  const dispatch = useDispatch();

  axios.interceptors.request.use((req) =&gt; {
    return req;
  });
  axios.interceptors.response.use((res) =&gt; {
    return res;
  });
  axios.interceptors.response.use(
    (res) =&gt; res,
    (err) =&gt; {
      console.log(&quot;##### AXIOS ERROR #####&quot;);
      dispatch(increment());
    }
  );

  return null;
};

export default useAxiosInterceptor;

<!-- end snippet -->

store.js

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

import { configureStore } from &quot;@reduxjs/toolkit&quot;;
import counterReducer from &quot;./counterSlice&quot;;

export default configureStore({
  reducer: {
    counter: counterReducer,
  },
});

<!-- end snippet -->

counterSlice.js

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

import { createSlice } from &quot;@reduxjs/toolkit&quot;;

export const counterSlice = createSlice({
  name: &quot;counter&quot;,
  initialState: {
    value: 0,
  },
  reducers: {
    increment: (state) =&gt; {
      // Redux Toolkit allows us to write &quot;mutating&quot; logic in reducers. It
      // doesn&#39;t actually mutate the state because it uses the Immer library,
      // which detects changes to a &quot;draft state&quot; and produces a brand new
      // immutable state based off those changes
      state.value += 1;
    },
    decrement: (state) =&gt; {
      state.value -= 1;
    },
    incrementByAmount: (state, action) =&gt; {
      state.value += action.payload;
    },
  },
});

// Action creators are generated for each case reducer function
export const { increment, decrement, incrementByAmount } = counterSlice.actions;

export default counterSlice.reducer;

<!-- end snippet -->

package.json

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

{
  &quot;name&quot;: &quot;react&quot;,
  &quot;version&quot;: &quot;1.0.0&quot;,
  &quot;description&quot;: &quot;React example starter project&quot;,
  &quot;keywords&quot;: [
    &quot;react&quot;,
    &quot;starter&quot;
  ],
  &quot;main&quot;: &quot;src/index.js&quot;,
  &quot;dependencies&quot;: {
    &quot;@reduxjs/toolkit&quot;: &quot;^1.9.2&quot;,
    &quot;axios&quot;: &quot;^1.3.2&quot;,
    &quot;react&quot;: &quot;18.2.0&quot;,
    &quot;react-dom&quot;: &quot;18.2.0&quot;,
    &quot;react-redux&quot;: &quot;^8.0.5&quot;,
    &quot;react-scripts&quot;: &quot;^5.0.1&quot;
  },
  &quot;devDependencies&quot;: {
    &quot;@babel/runtime&quot;: &quot;7.13.8&quot;,
    &quot;typescript&quot;: &quot;4.1.3&quot;
  },
  &quot;scripts&quot;: {
    &quot;start&quot;: &quot;react-scripts start&quot;,
    &quot;build&quot;: &quot;react-scripts build&quot;,
    &quot;test&quot;: &quot;react-scripts test --env=jsdom&quot;,
    &quot;eject&quot;: &quot;react-scripts eject&quot;
  },
  &quot;browserslist&quot;: [
    &quot;&gt;0.2%&quot;,
    &quot;not dead&quot;,
    &quot;not ie &lt;= 11&quot;,
    &quot;not op_mini all&quot;
  ]
}

<!-- end snippet -->

I hope that helps!

huangapple
  • 本文由 发表于 2023年2月8日 20:45:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/75386000.html
匿名

发表评论

匿名网友

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

确定