Javascript 将参数从一个Axios请求传递到另一个Axios请求

Javascript 将参数从一个Axios请求传递到另一个Axios请求,javascript,react-native,rest,redux,axios,Javascript,React Native,Rest,Redux,Axios,背景 我正在将内置的React Native应用程序连接到REST API。我通过Axios处理请求,并使用Redux存储查询结果。我有一个用于api连接的index.js文件,其中包含了一些函数,这些函数充当需要越来越深级别授权的请求的处理程序。我有一个简单的函数,返回一个访问令牌,这是由以下代码触发的,当前位于应用程序的“欢迎页面” 理想情况下,在浏览几个屏幕后,用户将进入主页并触发以下代码: useEffect(() => { dispatch(retrieveData())

背景

我正在将内置的React Native应用程序连接到REST API。我通过Axios处理请求,并使用Redux存储查询结果。我有一个用于api连接的index.js文件,其中包含了一些函数,这些函数充当需要越来越深级别授权的请求的处理程序。我有一个简单的函数,返回一个访问令牌,这是由以下代码触发的,当前位于应用程序的“欢迎页面”

理想情况下,在浏览几个屏幕后,用户将进入主页并触发以下代码:

useEffect(() => {
    dispatch(retrieveData());
  }, [dispatch]);
到目前为止,一切顺利。以下是调度触发的功能:

 export const getToken = () =>
      apiInstance
        .request({
          url: ENDPOINTS.TOKEN,
          data: qs.stringify({
            grant_type: 'some_credentials',
            c_id: 'some_id',
            c_secret: 'some_secret',
          }),
          headers: {
            'content-type': 'some_content_type',
          },
          method: 'POST',
        })
        .then(response => {
          return response.data;
        })
        .catch(error => {
          return Promise.reject(error.message);
        });

export const getData = () =>
  apiInstance
    .request({
      url: ENDPOINTS.DATA,
      method: 'POST',
      data: qs.stringify({
        timestamp: Date.now(),
        c_id: 'some_id',
        token: **this is the token we get from the previous function**,
      }),
      headers: {
        'content-type': 'some_content_type',
      },
    })
    .then(response => {
      return response.data;
    })
    .catch(error => {
      return Promise.reject(error.message);
    });
问题

正如我前面提到的,这是一个Redux/Axios解决方案。这意味着状态是全局存储的,但有一个执行顺序。您应该注意到,这两个函数存储在同一个文件中,除非像我之前展示的两个分派调用那样明确说明,否则不会调用它们

问题是,如果我从家中记录令牌(在使用dispatch调用它之后),我可以清楚地看到它,但是如果我尝试从存储请求函数的文件中记录所述令牌,我会得到一个空数组。我尝试用以下所有方法填充令牌字段:

  • const state=store.getState() 令牌:state.token
  • const getData=(令牌)=>{ ... 令牌:令牌} 并在dispatch中将令牌作为参数传递
  • 我还试着用菊花链将不同的调度链接起来,以强制执行 在检索令牌之后而不是之前获取数据
  • 问题

    如何从另一个axios查询中按特定顺序访问axios查询的结果

    需要注意的是,API中的数据只能通过POST访问,并且在执行getData()时得到的错误代码是401,即不正确的凭据。 另外,请记住这是一个Redux应用程序。查询结果以全局状态存储。但是,无法从外部组件访问此状态,并且我无法从执行查询的文件调用它,因为标记“在该时间点不存在”

    操作代码

    import keyMirror from 'keymirror';
    import {createAction} from 'redux-actions';
    import {getToken} from '../../api';
    
    export const tokenActionTypes = keyMirror({
      RETRIEVE_TOKEN_REQUEST: null,
      RETRIEVE_TOKEN_SUCCESS: null,
      RETRIEVE_TOKEN_FAILURE: null,
    });
    
    const tokenActionCreators = {
      request: createAction(tokenActionTypes.RETRIEVE_TOKEN_REQUEST),
      success: createAction(tokenActionTypes.RETRIEVE_TOKEN_SUCCESS),
      failure: createAction(tokenActionTypes.RETRIEVE_TOKEN_FAILURE),
    };
    
    export const retrieveToken = () => dispatch => {
      dispatch(tokenActionCreators.request());
      getToken()
        .then(token => dispatch(tokenActionCreators.success(token)))
        .catch(error => dispatch(tokenActionCreators.failure(error)));
    };
    
    import {tokenActionTypes} from '../actions/token';
    
    export const initialState = {
      loadingToken: false,
      token: [],
      error: null,
    };
    
    const actionsMap = {
      [tokenActionTypes.RETRIEVE_TOKEN_REQUEST]: state => ({
        ...state,
        loadingToken: true,
      }),
    
      [tokenActionTypes.RETRIEVE_TOKEN_SUCCESS]: (state, action) => ({
        ...state,
        loadingToken: false,
        token: action.payload,
      }),
    
      [tokenActionTypes.RETRIEVE_TOKEN_FAILURE]: (state, action) => ({
        ...state,
        loadingToken: false,
        error: action.payload,
      }),
    };
    
    export default (state = initialState, action) => {
      const actionHandler = actionsMap[action.type];
      if (!actionHandler) {
        return state;
      }
      return actionHandler(state, action);
    };
    
    减速器代码

    import keyMirror from 'keymirror';
    import {createAction} from 'redux-actions';
    import {getToken} from '../../api';
    
    export const tokenActionTypes = keyMirror({
      RETRIEVE_TOKEN_REQUEST: null,
      RETRIEVE_TOKEN_SUCCESS: null,
      RETRIEVE_TOKEN_FAILURE: null,
    });
    
    const tokenActionCreators = {
      request: createAction(tokenActionTypes.RETRIEVE_TOKEN_REQUEST),
      success: createAction(tokenActionTypes.RETRIEVE_TOKEN_SUCCESS),
      failure: createAction(tokenActionTypes.RETRIEVE_TOKEN_FAILURE),
    };
    
    export const retrieveToken = () => dispatch => {
      dispatch(tokenActionCreators.request());
      getToken()
        .then(token => dispatch(tokenActionCreators.success(token)))
        .catch(error => dispatch(tokenActionCreators.failure(error)));
    };
    
    import {tokenActionTypes} from '../actions/token';
    
    export const initialState = {
      loadingToken: false,
      token: [],
      error: null,
    };
    
    const actionsMap = {
      [tokenActionTypes.RETRIEVE_TOKEN_REQUEST]: state => ({
        ...state,
        loadingToken: true,
      }),
    
      [tokenActionTypes.RETRIEVE_TOKEN_SUCCESS]: (state, action) => ({
        ...state,
        loadingToken: false,
        token: action.payload,
      }),
    
      [tokenActionTypes.RETRIEVE_TOKEN_FAILURE]: (state, action) => ({
        ...state,
        loadingToken: false,
        error: action.payload,
      }),
    };
    
    export default (state = initialState, action) => {
      const actionHandler = actionsMap[action.type];
      if (!actionHandler) {
        return state;
      }
      return actionHandler(state, action);
    };
    

    您可以将一个thunk组合到另一个thunk中,如将get token组合到get data中:

    export const retrieveToken = () => (dispatch, getState) => {
      //you could use getState() to see if you need to fetch the token
      // const tokenResult = selectToken(getState());
      // if(token && !token expired) { return Promise.resolve() }
      dispatch(tokenActionCreators.request());
      //return a promise so you can wait for it
      return getToken()
        .then(token => dispatch(tokenActionCreators.success(token)))
        .catch(error => dispatch(tokenActionCreators.failure(error)));
    };
    //in retrieve data you can wait for the token
    export const retrieveData = () => dispatch => {
      dispatch(retrieveToken()).then(
        ()=>{
          //here return getting the data
        }
      )
    };
    
    该代码中的一个可能错误是,一个渲染周期将发送多个thunk,这些thunk将多次获取令牌。您可以通过retrieveToken操作解决此问题,该操作具有在解析时失效的缓存:

    const invalidateOnResolveCache = (cache = new Map()) => {
      return {
        get: (key) => cache.get(key),
        set: (key, value) => cache.set(key, value),
        resolved: (x) => cache.delete(key),
      };
    };
    
    或者,您可以为需要令牌的所有Thunk编写一个wrap函数:

    //group retrieveToken in such a way that if it's called multiple times
    //  during a render cycle the token request will only be made once
    //https://gist.github.com/amsterdamharu/2dde4a6f531251f3769206ee44458af7
    export const needsToken =
      (fn) =>
      (...args) =>
      (dispatch, getState) =>
        dispatch(retrieveToken(...args)).then(() =>
          //you could use getState to get the token and pass it to
          //  fn together with the other args
          // for example: fn(...args.concat(selectToken(getState())))
          fn(...args)
        );
    export const autoTokenRetrieveData = needsToken(retrieveData);
    //use needsToken for any other thunk actions that need a token
    
    例如:

    const{Provider,useDispatch,useSelector}=ReactRedux;
    const{createStore,applyMiddleware,compose}=Redux;
    const{createSelector}=重新选择;
    //分组代码以对操作进行分组
    //群承诺返回函数
    常量创建组=
    (缓存)=>
    (fn,getKey=(…x)=>JSON.stringify(x))=>
    (…args)=>{
    const key=getKey(args);
    让result=cache.get(key);
    如果(结果){
    返回结果;
    }
    //无缓存
    结果=Promise.resolve(fn.apply(null,args))。然后(
    (r) =>{
    cache.resolved(key);//告诉缓存承诺完成
    返回r;
    },
    (e) =>{
    cache.resolve(key);//告诉缓存承诺完成
    退回承诺。拒绝(e);
    }
    );
    cache.set(键、结果);
    返回结果;
    };
    //thunk动作创建者不是(…args)=>结果,而是
    //(…args)=>(调度,getState)=>结果
    //下面是我们如何将thunk动作分组的
    const createGroupedThunkAction=(thunkAction,缓存)=>{
    const group=createGroup(缓存)(
    (args、dispatch、getState)=>
    thunkAction.apply(null,args)(dispatch,getState)
    );
    返回(…参数)=>
    (调度,getState)=>{
    返回组(args、dispatch、getState);
    };
    };
    常量createInvalidateOnResolveCache=(
    缓存=新映射()
    ) => {
    返回{
    get:(key)=>cache.get(key),
    set:(键,值)=>cache.set(键,值),
    已解析:(键)=>cache.delete(键),
    };
    };
    //获取令牌的函数
    const uniqueToken=(
    (令牌)=>()=>
    代币++
    )(1);
    const fetchToken=()=>Promise.resolve(uniqueToken());
    常量初始状态={
    数据1:[],
    数据2:[],
    令牌:null,
    };
    //动作类型
    const DATA_SUCCESS='DATA_SUCCESS';
    const GOT_TOKEN='GOT_TOKEN';
    //动作创造者
    const dataSuccess=(数据,键)=>({
    类型:DATA_SUCCESS,
    有效负载:{key,data},
    });
    const gotToken=(令牌)=>({
    类型:GOT_TOKEN,
    有效载荷:令牌,
    });
    const reducer=(状态,{type,payload})=>{
    如果(类型===数据\u成功){
    const{data,key}=有效载荷;
    返回{
    ……国家,
    [键]:数据,
    };
    }
    如果(类型===GOT\u令牌){
    返回{
    ……国家,
    代币:{
    值:有效载荷,
    已创建:Date.now(),
    },
    };
    }
    返回状态;
    };
    //thunk获取数据
    const getData1=(令牌)=>(分派)=>
    Promise.resolve()然后(()=>
    派遣(
    数据成功(
    `已获取带有标记的数据1:${token}`,
    “数据1”
    )
    )
    );
    const getData2=(令牌)=>(分派)=>
    Promise.resolve()然后(()=>
    派遣(
    数据成功(
    `已获取带有标记的数据2:${token}`,
    “数据2”
    )
    )
    );
    //thunk正在获取令牌:
    常量getToken=()=>(调度)=>
    fetchToken()。然后((token)=>dispatch(gotToken(token));
    //分组thunk获取令牌
    常量getTokenGrouped=createGroupedThunkAction(
    格托克,
    createInvalidateOnResolveCache()
    );
    尼德斯托克常数=
    (fn)=>
    (…args)=>
    (调度,getState)=>{
    让承诺;
    //仅当令牌的时间超过1秒时才获取该令牌
    const tokenResult=selectToken(getState());
    如果(
    标记结果&&
    Date.now()-新日期(tokenResult.created).getTime()<
    1000
    ) {
    promise=promise.resolve();
    }否则{
    允诺