web-dev-qa-db-ja.com

Reactフック:axiosインターセプターを使用してグローバルスピナーを表示しますか?

ReactでAPI呼び出しが行われるたびにレンダリングされるローダーコンポーネントを追加したいと思います。 reduxの代わりにreact context + hooksを使用したい。

反応フックのルールが言うように、反応コンポーネントの外で反応フックを使用すべきではありません。しかし、私はSHOW_LOADERおよびHIDE_LOADER以下のAxiosインターセプター内。

これを達成する方法はありますか?

import axios from "axios";
axios.interceptors.request.use(
  config => {
    dispatch({
    type: "SHOW_LOADER"
})
    return config;
  },
  error => {
     dispatch({
    type: "HIDE_LOADER"
})
    return Promise.reject(error);
  }
);

axios.interceptors.response.use(
  response => {
    dispatch({
    type: "HIDE_LOADER"
})
    return response;
  },
  error => {
    dispatch({
    type: "HIDE_LOADER"
})
    return Promise.reject(error);
  }
);
function GlobalLoader(){
    const [state,dispatch] = useContext(LoaderContext);
    return(
        <div>
            {
                state.loadStatus &&
                    <Loader
                    type = "Puff"
                    color = "#00BFFF"
                    height = {100}
                    width = {100}
                    timeout = {3000} />
            }
        </div>
    );
}

export default GlobalLoader;

さらに情報が必要な場合はお知らせください:)

2
CodeZombie

axios.create(config)を使用してaxiosインスタンスを作成します。 useEffect()内でこのインスタンスを使用して、状態に影響を与える可能性のあるインターセプターを追加します(リデューサーはここではやりすぎです)。ここでインスタンスをどこでも使用すると、インターセプターによって状態が変化します。

注:複数のリクエストが開始/終了する可能性があるため、カウンタを使用する必要があります。要求に応じて増加し、応答に応じて減少します。カウンターが0でない場合、アプリケーションはロードされています。

const { useState, useCallback,useMemo, useRef, useEffect } = React;

const ax = axios.create(); // export this and use it in all your components

const useAxiosLoader = () => {
  const [counter, setCounter] = useState(0);
  
  const inc = useCallback(() => setCounter(counter => counter + 1), [setCounter]); // add to counter
  const dec = useCallback(() => setCounter(counter => counter - 1), [setCounter]); // remove from counter
  
  const interceptors = useMemo(() => ({
    request: config => (inc(), config),
    response: response => (dec(), response),
    error: error => (dec(), Promise.reject(error)),
  }), [inc, dec]); // create the interceptors
  
  useEffect(() => {
    // add request interceptors
    ax.interceptors.request.use(interceptors.request, interceptors.error);
    // add response interceptors
    ax.interceptors.response.use(interceptors.response, interceptors.error);
    return () => {
      // remove all intercepts when done
      ax.interceptors.request.eject(interceptors.request);
      ax.interceptors.request.eject(interceptors.error);
      ax.interceptors.response.eject(interceptors.response);
      ax.interceptors.response.eject(interceptors.error);
    };
  }, [interceptors]);
  
  return [counter > 0];
};

const GlobalLoader = () => {
    const [loading] = useAxiosLoader();
    
    return(
      <div>
      {
        loading ? 'loading' : 'not loading'
      }
      </div>
    );
}

// make a request by using the axios instance
setTimeout(() => {
  ax.get('https://swapi.co/api/people/1');
  ax.get('https://swapi.co/api/people/2');
  ax.get('https://swapi.co/api/people/3');
}, 1000);

ReactDOM.render(
  <GlobalLoader />,
  root
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.0/axios.js"></script>
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>
5
Ori Drori