-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
In our codebase, we have some thunk that trigger another thunk.
Example:
const getEmployer = createAsyncThunk('getEmployer', () => {
// retrieve employer of from current user
})
const getEmployee = createAsyncThunk('getEmployee', ({id}) => {
// retrieve employee of from employer's id
})
const getColleagues = createAsyncThunk('getColleagues', ({}, {dispatch, signal}) => {
if (signal.aborted) {
return;
}
const employerThunk = dispatch(getEmployer())
signal.addEventListener('abort', () => {
employerThunk.abort()
})
const employer = await employerThunk.unwrap()
if (signal.aborted) {
return;
}
const employeeThunk = dispatch(getEmployee({id: employer.id}))
signal.addEventListener('abort', () => {
employeeThunk.abort()
})
return employeeThunk.unwrap()
})
useEffect(() => {
const colleagueThunk = dispatch(getColleagues())
setTimeout(() => {
cooleagueThunk.abort()
}, 1000)
}, [])
to successfully abort those inner thunk we need to add a hand full of code
if possible, can we pass the AbortSignal somehow to the action creator itsel and then RTK handle can handle them?
const getEmployer = createAsyncThunk('getEmployer', () => {
// retrieve employer of from current user
})
const getEmployee = createAsyncThunk('getEmployee', ({id}) => {
// retrieve employee of from employer's id
})
const getColleagues = createAsyncThunk('getColleagues', ({}, {dispatch, signal}) => {
if (signal.aborted) {
return;
}
// passing signal from parent thunk
// even better if rtk can detect that signal already aborted and omit the thunk
// like how condition behave.
const employer = dispatch(getEmployer(undefined, {signal})).unwrap()
if (signal.aborted) {
return;
}
// passing signal from parent thunk
return dispatch(getEmployee({id: employer.id}, {signal})).unwrap()
})
useEffect(() => {
const timeout = AbortSginal.timeout(1000);
// passing signal from parent code.
dispatch(getColleagues(undefined, {signal}));
}, [])
I think this change align with the ecosystem as most API that support AbortSginal/AbortController allow receive AbortSginal from invoke method.
My main concern with above suggestion is that the interface is a little bit wonky for action creator without argument.
Another interface we can explore is withMeta
property, similar to the pending
, rejected
, fullfilled
action type reference. But now the meta like signal will be alway be the first argument, the action creator argument will be the 2nd argument if they need. It also allow caller to pass meta information to reducer.
const getEmployer = createAsyncThunk('getEmployer', () => {
// retrieve employer of from current user
})
const getEmployee = createAsyncThunk('getEmployee', ({id}) => {
// retrieve employee of from employer's id
})
const getColleagues = createAsyncThunk('getColleagues', ({}, {dispatch, signal}) => {
// asumpt rtk already handle Canceling Before Execution with signal
const employer = dispatch(getEmployer.withMeta({signal})).unwrap()
return dispatch(getEmployee.withMeta({signal}, {id: employer.id})).unwrap()
})
useEffect(() => {
const timeout = AbortSginal.timeout(1000);
// passing signal from parent code.
dispatch(getColleagues.withMeta({signal}));
}, [])