使用axios示例通过redux形实转换操作访问useAuth0钩子数据

kulphzqa  于 2022-11-23  发布在  iOS
关注(0)|答案(1)|浏览(143)

bounty将在11小时后过期。回答此问题可获得+200声望奖励。mcclosa希望吸引更多人关注此问题。

在当前架构下尝试获取登录用户的Auth 0信息时遇到了一些问题。
我们有redux@reduxjs/toolkit & react-redux作为状态管理工具。
我们使用axios通过redux-thunk操作发出HTTP请求。
现在,我们的应用程序中有一部分允许用户使用Auth0注册/登录。
那么,我们的问题的一个例子。
目前,我们的redux商店设置了一些还原器

/* eslint-disable import/no-cycle */
import { configureStore } from '@reduxjs/toolkit';
import thunk from 'redux-thunk';

const createStore = (initialState?: any) => {
  return configureStore({
    reducer: {
      // reducers are here
    },
    middleware: [thunk],
    preloadedState: initialState,
  });
};

export default createStore;

然后,我们将其附加到应用程序底部的Provider

import React from 'react';
import { Provider } from 'react-redux';
import createStore from '../store/createStore';

const App = () => {
  return (
      <Provider store={createStore()}>
        //
      </Provider>
  );
};
export default App;

我们有一个axios示例函数,它使用axios发出HTTP请求并处理错误。

import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
import { getAuthSignature } from '../utils/auth';

export const API_URL = process.env.API_HOST;

const axiosInstance = async <T = any>(requestConfig: AxiosRequestConfig): Promise<AxiosResponse<T>> => {
  const { token } = await getAuthSignature();
  // I need to access auth0 data here
  const { getAccessTokenSilently, isAuthenticated, isLoading, loginWithRedirect, user } = auth0;

  if (!token) {
    const tokenErr = {
      title: 'Error',
      message: 'Missing Authentication Token',
      success: false,
    };
    throw tokenErr;
  }

  try {
    let accessToken = token;
    // Update authorization token if auth0 user
    if(auth0) {
      if(isAuthenticcation && user) accessToken = await getAccessTokenSilently({ audience });
      else loginWithRedirect();
    }
    const result = await axios({
      ...requestConfig,
      headers: {
        ...requestConfig.headers,
        authorization: `Bearer ${accessToken}`,
      },
    });

    return result;
  } catch (error: any) {
    if (error.response) {
      if ([401, 403].includes(error.response.status)) {
        window.location = '/';
      }

      const contentType = error?.response?.headers?.['content-type'];
      const isHTMLRes = contentType && contentType.indexOf('text/html') !== -1;

      const errObj = {
        status: error?.response?.status,
        statusText: error?.response?.statusText,
        errorMessage: isHTMLRes && error?.response?.text && (await error?.response?.text()),
        error,
      };

      throw errObj;
    }

    throw error;
  }
};

export default axiosInstance;

这是一个thunk操作的例子,我们将使用上面提到的axios示例来发出HTTP请求。

import axios, { API_URL } from '../../services/axios';
import { Result } from '../../types/test';
import { AppThunk } from '../../store/store';
import { setResults, setResultsLoading, setTableLoading } from './test.slice';

type DefaultThunk = () => AppThunk<Promise<void>>;

const getResults: DefaultThunk = () => async () => {
  dispatch(setTableLoading(true));

  try {
    const result = await axios<Result[]>(
      {
        method: 'GET',
        url: `${API_URL}/test`,
      },
    );

    dispatch(setResults(result.data));
  } catch (err: any) {
    console.log({ err });
  } finally {
    dispatch(setResultsLoading(false));
    dispatch(setTableLoading(false));
  }
};

export default getResults;

然后,我们分派thunk操作来发出HTTP请求并更新React组件中的reducer状态。

import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import getResults from '../../reducers/test/test.thunk';

const TestComponent = () => {
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(getResults());
  }, []);

  return (
    //
  );
};

export default TestComponent;

我的问题是,我不知道如何将Auth0优雅地集成到当前流中,因此我不必在每个使用thunk操作的react组件中进行检查。
基本上,我需要从@auth0/auth0-react访问useAuth0钩子中的值,例如getAccessTokenSilentlyisAuthenticateduserloginWithRedirect
我们不能在axios示例文件中使用useAuth0钩子,因为它不是react组件/钩子,thunk文件也不是。
因此,我不确定如何以及在哪里获取数据,以便在axios文件中访问数据,如前所述,而不必在每个redux thunk操作中将其作为参数或其他东西传递。
也许我们只是需要一种不同的方法来处理当前的调度〉操作〉axios请求的流程?
有没有办法将这些数据作为中间件传递给redux?
任何帮助都将不胜感激。

2w3rbyxf

2w3rbyxf1#

我不相信你能够使用中间件来“嗅出”auth0上下文值,因为中间件运行在React的 * 外部a。这里我建议创建一个位于Auth0Provider和redux Provider组件之间的 Package 器组件,该组件访问auth0上下文,并分派一个操作将其保存到redux状态,在redux状态下可以通过useSelector或直接从store.getState()访问。
幸运的是,auth0上下文值似乎已经存储在这里,因此它应该能够作为应用程序中的一个稳定引用直接使用。
粗略示例:

import { useDispatch } from 'react-redux';
import { useAuth0 } from '@auth0/auth0-react';
import { actions } from '../path/to/auth0Slice';

const Auth0Wrapper = ({ children }) => {
  const dispatch = useDispatch();

  const auth0 = useAuth0();

  useEffect(() => {
    dispatch(actions.setAuthContext(auth0));
  }, [auth0]);

  return children;
};

创建并导出商店以在应用程序中使用。
商店

import { configureStore } from '@reduxjs/toolkit';
import thunk from 'redux-thunk';
import { combineReducers } from 'redux';
...
import auth0Reducer from '../path/to/auth0Slice';
...

const rootReducer = combineReducers({
  auth0: auth0Reducer,
  ... other root state reducers ...
});

const createStore = (initialState?: any) => {
  return configureStore({
    reducer: rootReducer,
    middleware: [thunk],
    preloadedState: initialState,
  });
};

export default createStore;

应用程序

import Auth0Wrapper from '../path/to/Auth0Wrapper';
import createStore from '../path/to/store';

const store = createStore();

const App = () => {
  return (
    <Auth0Provider ......>
      <Provider store={store}>
        <Auth0Wrapper>
          // ... JSX ...
        </Auth0Wrapper>
      </Provider>
    </Auth0Provider>
  );
};

export store;

export default App;

建立新的Auth0状态磁盘片段。

import { createSlice } from '@reduxjs/toolkit';

const auth0Slice = createSlice({
  name: 'auth0',
  initialState: {},
  reducers: {
    setAuthContext: (state, action) => {
      return action.payload;
    },
  },
});

export const actions = {
  ...auth0Slice.actions,
};

export default auth0Slice.reducer;

在这里,您可以导入导出的store对象,并访问axios设置中的当前状态。

import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
import store from '../path/to/App';
import { getAuthSignature } from '../utils/auth';

export const API_URL = process.env.API_HOST;

const axiosInstance = async <T = any>(requestConfig: AxiosRequestConfig): Promise<AxiosResponse<T>> => {
  const { token } = await getAuthSignature();

  const { auth0 } = store.getState(); // <-- access current state from store

  const {
    getAccessTokenSilently,
    isAuthenticated,
    isLoading,
    loginWithRedirect,
    user
  } = auth0;

  ...
};

相关问题