Reputation: 7642
I have some issues with this createAsyncThunk
from the redux toolkit API
export const getPayments = createAsyncThunk('getPayments/all', async ({ rejectWithValue }) => {
try {
const response = await fetch(`/payments`, {
method: 'GET',
headers: { 'Content-Type': 'application/json' },
})
console.log('res:', response)
return response
} catch (e) {
console.log('ERROR:', e)
rejectWithValue(e)
}
})
Whenever I add rejectWithValue
as a parameter, it ALWAYS shows as rejected in the redux devtools. and when I remove it, it's ALWAYS fulfilled. what is going on here? I just want to call this function below if there is an error from the fetch? why is it always rejecting it?
EDIT: I am seeing this Cannot destructure property 'rejectWithValue' of 'undefined' as it is undefined.
in the response now, which makes sense why it's always rejected, why is this happening though and how do I fix it?
Upvotes: 1
Views: 1874
Reputation: 39250
Here is an example how you can do it, as commented the rejectWithValue
of the payload creator is a property of the second argument and the payload creator needs to return the result of the rejectWithValue
call, here is an example:
// toggle reject
const reject = ((shouldReject) => () =>
(shouldReject = !shouldReject))(true);
// test thunk action creator
const testAsyncThunk = createAsyncThunk(
'some/test',
// arg is the argument passed to the action creator, can be ignored if not used
async (arg, { rejectWithValue }) => {
console.log('argument passed to action creator:', arg);
if (reject()) {
//return result of rejectWithValue call
return rejectWithValue('rejected');
}
return Promise.resolve('resolved');
}
);
When you dispatch a thunk created with createAsyncThunk
the resulting promise will not reject unless you use unwrapResult
.
Here is a minimal app demonstrating the behaviour:
import React from 'react';
import ReactDOM from 'react-dom';
import {
createAsyncThunk,
unwrapResult,
} from '@reduxjs/toolkit';
import { Provider, useDispatch } from 'react-redux';
import {
createStore,
applyMiddleware,
compose,
} from 'redux';
// toggle reject
const reject = ((shouldReject) => () =>
(shouldReject = !shouldReject))(true);
// test thunk action creator
const testAsyncThunk = createAsyncThunk(
'some/test',
// arg is the argument passed to the action creator, can be ignored if not used
async (arg, { rejectWithValue }) => {
console.log('argument passed to action creator:', arg);
if (reject()) {
//return result of rejectWithValue call
return rejectWithValue('rejected value');
}
return Promise.resolve('resolved value');
}
);
const reducer = (state, { type, payload }) => {
return state;
};
//creating store with redux devtools and thunk middleware
const composeEnhancers =
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
reducer,
{},
composeEnhancers(
applyMiddleware(
({ dispatch, getState }) => (next) => (action) =>
//minimal implementation of thunk middleware
typeof action === 'function'
? action(dispatch, getState)
: next(action)
)
)
);
const App = () => {
const dispatch = useDispatch();
return (
<button
onClick={() =>
dispatch(testAsyncThunk('argument passed'))
.then(
(resolved) => {
console.log('action resolved with', resolved);
return resolved;
},
(rejected) =>
// this never executes because promise returned
// by dispatch(tunkaction) will not reject
console.log('action rejected with:', rejected)
)
.then(
//after unwrap result you have a promise that will
// reject
unwrapResult
)
.catch((err) =>
console.log('rejected with...', err)
)
}
>
dispatch action
</button>
);
};
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
Upvotes: 3