Another way to work with Promise for Redux
It turned out that at the moment I am taking part in the development of a front-end application (React + Redux) that makes a lot of requests to the REST API every minute, if not second.
I’m tired of writing REQUEST / FAILURE / SUCCESS (hereinafter RFS) actions for every request, cases for them for the reducer, all this is plentifully watered with tests (quality is above all else).
I wrote another bike.

Existing problem
A lot of libraries have already been written for convenient work with RFS, but they involve a detailed setup of each of the three actions + writing cases for the reducer + tests. Basically, these libraries can be used in 100% of cases when writing requests to the server. Such flexibility requires writing a ton of code for similar tasks.
In the project that I am currently working on, 90% of requests perform an extremely simple task: go to the server, take the data, convert it a bit, put it in state , if something went wrong - complain. Thousands of test lines have been written, which are inherently copy-paste with micro-changes.
To the point
How long? Weekends in front of the monitor, a liter of coffee, a shawarma for lunch and dinner, a little controlled magic ...

... the library is ready.
The fromTo function (from, to, [through]) will take the data where it is said, convert it as it should, and put it in the specified location (any in your state , but only if you use the immutable library for the reducer ). The reducer will independently (after wrapping it in fromTo.wrapper) understand how to work with data and predictably change state in accordance with RFS actions (which the library will take care of itself). Everything is covered with tests (if you find bugs, push mercilessly or open a ticket ).
Feature Summary
The simplest way (this is about half the time on our project) using fromTo action is:
// запрос к серверу возвращает {"mood": "happy"} , HTTP200
dispatch(fromTo(
() => axios.get('dogs.io/good-boy'),
['dogs', 'goodBoy'],
));Here is what will happen in your state at this time :
Initial state
{
...otherReducers,
dogs: Immutable.fromJS({}),
}REQUEST
{
...otherReducers,
dogs: Immutable.fromJS({
goodBoy: {
isRequesting: true,
},
}),
}SUCCESS
{
...otherReducers,
dogs: Immutable.fromJS({
goodBoy: {
isRequesting: false,
data: {
mood: 'happy',
},
},
}),
}For toanother 40% of cases, the object is used as an argument and a third (optional) argument is added. In eastern cases, we act in the old fashioned way ( fromTonot a panacea, but a convenient tool).
Function parsing fromTo(from, to, [through])
The function has 3 arguments.
from. We say where to get the data. Function that returns Promise. Will be called without arguments.to. We say where to save the data.- If you use the object as an argument, then you need 3 keys:
{ request, failure, success }. These are 3 coordinates for the data in your state , where they will be saved::requestcoordinates for the Boolean value whether the call was completedfrom(for example[ 'dogs', 'isFetching', 1 ]) ,:failurecoordinates for the data that returned whenreject(for example[ 'cats', 'errors', 2 ])success,: coordinates for the data that returned whenresolve(for example[ 'robots', 'data', 3 ]). - You can restrict yourself to a list (for example
[ 'goodBoy' ]), then this argument will be converted to an object{ request: [ 'goodBoy', 'is Requesting' ], failure: [ 'goodBoy', 'error' ], success: [ 'goodBoy', 'data' ] }
- If you use the object as an argument, then you need 3 keys:
[through]. We are talking (and we can not even talk and trust in defaults) how to convert the data that we returned to the investigationfrom(). An object can contain one or both of the methods:requestAdapter- a function that will receive input fromresolve. The returned data will be saved with SUCCESS,errorAdapter- a function that will receive input fromreject. The returned data will be saved with FAILURE.
Total
At the moment, on the project, we save hours of our time and bundles of nerves due to the lack of the need to write tons of monotonous code. Instead of 90% of actions, reducers, tests, one function is called dispatch(fromTo(...args)). We are glad.
Of course, a certain number of tests are still written, but basically these are tests for the argument through(required) and a tribute to TDD.
In the comments I would like to see the opinion of colleagues in the workshop, constructive criticism is more than welcome. Raw in a gita , library in an enpeem , a duck in a hare, a hare in a chest, and he is on a tree.
Have a nice day.