Redux-saga:从 redux 操作返回承诺

时间:2021-06-06 10:29:36

标签: reactjs redux react-redux redux-saga

我正在使用 redux-saga。我想调度一个动作并在之后立即使用该动作的结果。但是 saga 是异步调度的,之后结果不可用。

class A extends Component{
    handleEvent = (e) =>{
       this.props.getInfo(param);
       //Use Result(this.props.Info) from the action
    }
    render(){
    }
}
function mapStateToProps(state) {
    return {
        Info : state.infoReducer.info
    };
}
function mapDispatchToProps(dispatch) {
    return {
        getInfo : (val)=>{dispatch(getInfo(val))}          
    }
}
export default connect(mapStateToProps, mapDispatchToProps) (A); 

我的动作创建者:

export function getInfo(data){
    return{
        type : actionType.GET_INFO,
        payload : data
    }
}

Saga 函数:


function* getInfo(action){
    try {
     const response = yield call(post,Endpoint,param,header);
        const data =  yield response.data;
        if(error) yield put({type: GET_INFO_FAIL});
        else yield put({ type:  GET_INFO_SUCCESS, data });
        
    } catch (e) {
        //
    } 
}

减速器:

const INITIAL_STATE ={
    info : ""
}
const infoReducer=(state = INITIAL_STATE, action) => {
    switch (action.type) {
        case actionType.GET_INFO_SUCCESS:
        return{
            info : action.data
        }
        default:
            return state;
    }

}

1 个答案:

答案 0 :(得分:0)

您可以使用承诺创建动作创建者。将 resolvereject 函数作为元传递给动作创建者。然后在 API 调用完成后在 worker saga 中调用 resolvereject

我们可以创建 bindActionToPromise 辅助函数来做到这一点。

const bindActionToPromise = (dispatch, actionCreator) => (payload) => {
  return new Promise((resolve, reject) => dispatch(actionCreator(payload, { resolve, reject })));
};

function mapDispatchToProps(dispatch) {
    return {
        getInfo: bindActionToPromise(dispatch, getInfo)
    }
}

getInfo 工人传奇:

function* getInfoSaga(action) {
  console.log(action);
  const {
    meta: { resolve, reject },
  } = action;
  const response = yield call(apiCall);
  if (response.error) {
    yield put({ type: actionType.GET_INFO_FAIL });
    yield call(reject, response.error);
  } else {
    yield put({ type: actionType.GET_INFO_SUCCESS, data: response.data });
    yield call(resolve, response.data);
  }
}

然后,您可以像这样立即获得 API 响应:

 this.props.getInfo(param).then(res => console.log(res))

一个完整的工作示例:

import { call, put, takeLatest } from 'redux-saga/effects';
import { createStoreWithSaga } from '../../utils';

const actionType = { GET_INFO: 'GET_INFO', GET_INFO_FAIL: 'GET_INFO_FAIL', GET_INFO_SUCCESS: 'GET_INFO_SUCCESS' };

export function getInfo(payload, meta) {
  return {
    type: actionType.GET_INFO,
    payload,
    meta,
  };
}

function apiCall() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({ data: 'Info from API', error: null });
      //   resolve({ data: null, error: new Error('business error') });
    }, 1000);
  });
}

function* getInfoSaga(action) {
  console.log(action);
  const {
    meta: { resolve, reject },
  } = action;
  const response = yield call(apiCall);
  if (response.error) {
    yield put({ type: actionType.GET_INFO_FAIL });
    yield call(reject, response.error);
  } else {
    yield put({ type: actionType.GET_INFO_SUCCESS, data: response.data });
    yield call(resolve, response.data);
  }
}

function* watchSaga() {
  yield takeLatest(actionType.GET_INFO, getInfoSaga);
}

const INITIAL_STATE = {
  info: '',
};
const infoReducer = (state = INITIAL_STATE, action) => {
  switch (action.type) {
    case actionType.GET_INFO_SUCCESS:
      return {
        info: action.data,
      };
    default:
      return state;
  }
};

const store = createStoreWithSaga(watchSaga, infoReducer);

export const bindActionToPromise = (dispatch, actionCreator) => (payload) => {
  return new Promise((resolve, reject) => dispatch(actionCreator(payload, { resolve, reject })));
};

const boundGetInfo = bindActionToPromise(store.dispatch, getInfo);
boundGetInfo({ id: 1 })
  .then((res) => {
    console.log('res immediately: ', res);
  })
  .catch((err) => {
    console.log('error immediately: ', err);
  });
store.subscribe(() => {
  console.log('state: ', store.getState());
});

执行输出:

{
  type: 'GET_INFO',
  payload: { id: 1 },
  meta: { resolve: [Function (anonymous)], reject: [Function (anonymous)] }
}
state:  { info: 'Info from API' }
res immediately:  Info from API