Hi! I would like to know what a good approach is for reusing a generic Machine.
Say I’m building a CMS, and in each component I make one or more requests to create/update entities. I would like to reuse a generic ‘network request’ machine to keep track of which request is pending, has succeeded or has failed in order to update the UI.
What I'm currently doing is creating a new service using the interpreter for each request I need to make, passing different machine configurations using ‘withConfig’
import requestMachine from ‘./requestMachine’
const updateUserService = interpret(requestMachine.withConfig({
actions: {
performRequest: updateUser,
requestSuccess: showSuccessMessage,
requestFailure: showErrorMessage
}
})).start()
const createBlogPostService = interpret(requestMachine.withConfig({
actions: {
performRequest: createBlogPost,
requestSuccess: ...,
requestFailure: ...
}
})).start()
Am I on the right track or is there a better way?
Thanks!
What does the requestMachine look like?
Now its like this:
const requestMachine = Machine({
id: 'request',
strict: true,
initial: 'idle',
states: {
idle: {
on: {
REQUEST: {
target: 'pending',
actions: ['performRequest']
}
}
},
pending: {
on: {
SUCCESS: 'success',
FAILURE: 'failure'
}
},
success: {
after: {
1000: 'idle'
},
onEntry: ['requestSuccess']
},
failure: {
after: {
1000: 'idle'
},
onEntry: ['requestFailure']
}
}
})
However I was reading in another issue that it's better to use invoke instead of an action for actually performing the request since that will eventually affect the state of the machine, but I haven't understood how to change it yet...
With invoke, you can model a request like this:
const requestMachine = Machine({
id: 'request',
strict: true,
initial: 'idle',
states: {
idle: {
on: { REQUEST: 'pending' }
},
pending: {
invoke: {
src: (ctx, event) => fetchFromSomewhere(...),
onDone: 'success',
onError: 'failure'
}
},
// ...
}
});
You can make a function that returns a machine:
const createRequestMachine = (fetcher) => Machine({
// ...
invoke: {
src: (ctx, event) => fetcher(ctx, event)
// ...
}
// ...
});
const getUserMachine = createRequestMachine(fetchUser);
Lots of different ways you can approach this (it's just JS 😄)
Ok thanks now I get it!
I like the factory function approach to reuse and configure a machine.
Maybe it could be clearer in the docs that invoke is not only for "communicating between machines" (which is the title of the page), but it can also be used in situations such as this.