Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
An idea for actor-model-based effects with reducers
import {
useReducerWithEffects,
// hand-wavey, but meant to be used by React to create something
// external will produce async values sent to components
createEffect
} from 'react';
function fetchUserEffect(id, parentRef) {
const controller = new AbortController();
const signal = controller.signal;
const promise = fetch(`https://example.com/api/users/${id}`, { signal });
promise.then(
data => parentRef.send({ type: 'RESOLVE', data }),
error => parentRef.send({ type: 'REJECT', error })
);
return {
send(event) {
if (event.type === 'CANCEL') {
controller.abort();
parentRef.send({ type: 'CANCELLED' });
}
}
}
}
function fetchUserReducer(state, event, ownRef) {
if (event.type === 'FETCH') {
const fetchRef = createEffect(fetchUserEffect(ownRef));
return { ...state, status: 'fetching', fetchRef };
} else if (event.type === 'CANCEL') {
// tell fetchRef to cancel
state.fetchRef.send({ type: 'CANCEL' });
} else if (event.type === 'CANCELLED') {
return {
...state,
status: 'cancelled'
};
} else if (event.type === 'RESOLVE') {
return { ...state, user: event.data, status: 'resolved' };
} else {
return state;
}
}
const initialState = {
user: null,
error: null,
status: 'idle'
};
// In a component
const UserComponent = () => {
// Same syntax as useReducer()
const [state, dispatch] = useReducerWithEffects(fetchUserReducer, initialState);
// ...
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment