2017-01-17 16 views
3

Я недавно начал использовать саундресс, и мне это очень нравится.Как перенести api call wrapper из редукции thunk в саму редукцию

У меня есть следующая оболочка, которую я использую для своих вызовов api, которые будут выполнять обещание (мой вызов api) и отображать ошибки перед загрузчиком и обработкой.

export const callApi = (promise: Promise<any>, errorMsg: string = 'Api error') => (dispatch: Dispatch) => { 
    dispatch(setLoading(true)); 
    return promise.then(
    (response) => { 
     dispatch(setLoading(false)); 
     return response.body; 
    }, 
    (error) => { 
     dispatch(setLoading(false)); 
     dispatch(apiError(errorMsg, error)); 
     return error; 
    }); 
}; 

Я не уверен, как бы повторить такое поведение в саге редукции. Я не мог найти какой-либо пример такого действия?


До сих пор я придумал

const camelizeKeysPromise = (obj) => Promise.resolve(camelizeKeys(obj)); 


export function* sagaCallApi(promise: Promise<any>, errorMsg: string = 'Api error') { 
    yield put(setLoading(true)); 
    try { 
     const response = yield call(promise); 
     try { 
     const result = yield call(camelizeKeysPromise(response.body)); 
     return result; 
     } catch (e) { 
     return response.body; 
     } 
    } catch (exception) { 
     yield put(setLoading(false)); 
     yield put(apiError(errorMsg, error)); 
    }; 
} 

ответ

1

Уступая в call обещать не будет возвращать нужный ответ. Вы можете использовать eventChannel от redux-saga, чтобы создать канал, который испускает ответ на успех или объект ошибки при сбое, а затем подписаться на канал в вашей саге.

const promiseEmitter = promise => { 
    return eventChannel(emit => { 
    promise.then(
     response => emit({response}), 
     error => emit({error}) 
    ); 
    }); 
}; 

Измените новую сагу, заменив вызов на обещание с этим:

const channel = yield call(promiseEmitter, promise); 
const {response, error} = yield take(channel); 
if(response){ 
    // handle success 
    return response; 
}else if(error){ 
    // handle failure 
    yield put(setLoading(false)); 
    yield put(apiError(errorMsg, error)); 
} 

Имейте в виду, что могут быть синтаксические ошибки в своем коде, как я написал это без редактора, но вы можете получить общий подход.

+0

Спасибо за ваш ответ. Я только что читал по каналам. Я прав, думая, что это не понадобится, если вместо обещания я передам функцию, возвращающую обещание? – Tom

+0

Вероятно, у вас будет та же проблема, так как вы получите обещание, а не ответ, если вы дадите эффект вызова этой функции, если я не пропущу ваш вопрос. –