Skip to content

Instantly share code, notes, and snippets.

@burdiuz
Last active March 20, 2019 09:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save burdiuz/87b5d47a0c1dac57e7c0f3ac86f12378 to your computer and use it in GitHub Desktop.
Save burdiuz/87b5d47a0c1dac57e7c0f3ac86f12378 to your computer and use it in GitHub Desktop.
@actualwave/redux-promised-action - Promised action creator factory, uses redux-thunk to return promise from dispatch

@actualwave/redux-promised-action

Promised action creator factory, uses redux-thunk to return promise from redux dispatch(). It was made to be used with redux-saga but does not depend on it.

Also check redux-promise , official? way to handle promises.

How To

Define action creators:

// actions.js file
import { makeActionCreator, makePromisedActionCreator } from '@actualwave/redux-promised-action';


export const FETCH_DATA = 'FETCH_DATA';
export const FETCH_DATA_SUCCESS = 'FETCH_DATA_SUCCESS';
export const FETCH_DATA_FAILURE = 'FETCH_DATA_FAILURE';

// returns promise
export const fetchData = makePromisedActionCreator(FETCH_DATA);

// normal action creator, returns nothing
export const fetchDataSuccess = makeActionCreator(FETCH_DATA_SUCCESS);
export const fetchDataFailure = makeActionCreator(FETCH_DATA_FAILURE);

Use action creators:

// react component file
import { connect } from 'react-redux';
import { fetchData } from 'actions';

...

  componentDidMount() {
    const { fetch } = this.props;

    fetch({
	  url: '/api/data',
	}).then(this.handleDataLoaded);
  }

...

export default connect(
  null,
  {
    fetch: fetchData,
  },
)(MyComponent);

Actions created this way contain properties:

  • payload -- its whatever you put into first action creator argument.
  • meta -- its whatever you put into second action creator argument. If action creator was called without arguments, both properties will be empty objects.

For promised action meta object also contains promise with its own Promise returned from action creator, resolve and reject functions to resolve or reject that promise respectively. Take control of the promise in saga function:

function*  fetchDataSaga({ payload: { url }, meta: { resolve, reject } }) {
  try {
    yield put({ type: 'fetchData' });
    const response = yield call(fetchApi, url);
    
	const data = yield call(getDataFromResponse, response);
  
    yield put(fetchDataSuccess(data));
    yield call(resolve, data);
  } catch (error) {
    yield put(fetchDataFailure(error));
    yield call(reject, error);
  }
}

FYI, if you don't use redux-saga and want to achieve same effect with async action creators, using redux-thunk and async/await this approach may suit your needs:

const  fetchData  = ({ payload: { url } }) => async (dispatch) => {
    try {
      dispatch({ type: 'fetchData' });

      const response  =  await fetch(url);

      const data  =  await getDataFromResponse(response);

      dispatch(fetchDataSuccess(data));
      return data;
    } catch (error) {
      dispatch(fetchDataFailure(error));
      throw error;
    }
  };

Written with StackEdit.

{
"name": "@actualwave/redux-promised-action",
"description": "Promised action creator factory, uses redux-thunk to return promise from dispatch",
"version": "0.0.4",
"main": "promisedAction.js",
"dependencies": {
"@actualwave/deferred": "0.0.1"
},
"peerDependencies": {
"redux-thunk": "^2.3.0"
},
"keywords": [
"redux",
"thunk",
"action",
"creator",
"action creator",
"factory",
"payload",
"factory",
"function"
],
"author": {
"name": "Oleg Galaburda",
"email": "burdiuz@gmail.com",
"url": "http://actualwave.com/"
},
"bugs": {
"url": "https://gist.github.com/burdiuz/87b5d47a0c1dac57e7c0f3ac86f12378",
"email": "burdiuz@gmail.com"
},
"homepage": "https://gist.github.com/burdiuz/87b5d47a0c1dac57e7c0f3ac86f12378",
"license": "MIT"
}
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const { deferred } = require('@actualwave/deferred');
const actionCreator = (type, payload, meta) =>
({
type,
payload,
meta,
});
const makeActionCreator = (type) =>
(payload, meta) =>
actionCreator(type, payload, meta);
const makePromised = (actionCreator) =>
(type, payload, meta = {}) =>
(dispatch) => {
const control = deferred();
const { promise } = control;
Object.assign(meta, control);
dispatch(actionCreator(type, payload, meta));
return promise;
};
const promisedActionCreator = makePromised(actionCreator);
const makePromisedActionCreator = (type) =>
(payload, meta) =>
promisedActionCreator(type, payload, meta);
exports.makeActionCreator = makeActionCreator;
exports.makePromised = makePromised;
exports.makePromisedActionCreator = makePromisedActionCreator;
exports.isPromisedAction = ({ meta }) => meta && meta.promise && meta.resolve && meta.reject;
exports.resolvePromisedAction = ({ meta: { resolve }}, data) => resolve(data);
exports.rejectPromisedAction = ({ meta: { reject }}, data) => reject(data);
exports.getActionPromise = ({ meta: { promise }}) => promise;
exports.default = makePromisedActionCreator;
import deferred from '@actualwave/deferred';
const actionCreator = (type, payload, meta) =>
({
type,
payload,
meta,
});
export const makeActionCreator = (type) =>
(payload, meta) =>
actionCreator(type, payload, meta);
export const makePromised = (actionCreator) =>
(type, payload, meta = {}) =>
(dispatch) => {
const control = deferred();
const { promise } = control;
Object.assign(meta, control);
dispatch(actionCreator(type, payload, meta));
return promise;
};
const promisedActionCreator = makePromised(actionCreator);
export const makePromisedActionCreator = (type) =>
(payload, meta) =>
promisedActionCreator(type, payload, meta);
export const isPromisedAction = ({ meta }) => meta && meta.promise && meta.resolve && meta.reject;
export const resolvePromisedAction = ({ meta: { resolve }}, data) => resolve(data);
export const rejectPromisedAction = ({ meta: { reject }}, data) => reject(data);
export const getActionPromise = ({ meta: { promise }}) => promise;
export default makePromisedActionCreator;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment