This release introduces changes to error handling.
Previously, the parameter of the rejected promise callback was both the dispatched action and an error object. The middleware also always constructed a new error object, which caused unexpected mutation and circular references.
Now, the parameter of the rejected promise callback is the value of reject. The middleware does not construct a new error; it is your responsibility to make sure the promise is rejected with an Error object.
// before
const bar = () => ({
type: 'FOO',
payload: new Promise(() => {
reject('foo');
})
});.then(() => null, ({ reason, action }) => {
console.log(action.type): // => 'FOO'
console.log(reason.message); // => 'foo'
});
// after
const bar = () => ({
type: 'FOO',
payload: new Promise(() => {
/**
* Make sure the promise is rejected with an error. You
* can also use `reject(new Error('foo'));`. It's a best
* practice to reject a promise with an Error object.
*/
throw new Error('foo');
})
});.then(() => null, error => {
console.log(error instanceof Error); // => true
console.log(error.message); // => 'foo'
});
2.x to 3.0.0
This release introduces some major changes to the functionality of the middleware:
First, the middleware returns a promise instead of the action.
Third, promises can be explicitly or implicitly in the action object.
// before
const foo = () => ({
type: 'FOO',
payload: {
promise: Promise.resolve()
}
});
// after, with implicit promise as the value of the 'payload' property
const bar = () => ({
type: 'BAR',
payload: Promise.resolve()
});
Of course, if you prefer the explicit syntax, this still works. This syntax is also required for optimistic updates.
// after, but with explicit 'promise' property and 'data' property
const bar = () => ({
type: 'BAZ',
payload: {
promise: Promise.resolve(),
data: ...
}
});
Fourth, thunks are no longer bound to the promise. If you are chaining actions with Redux Thunk, this is critical change.