Skip to content
This repository has been archived by the owner on Dec 12, 2023. It is now read-only.

Allow for unimplemented actions/services/guards #32

Closed
mattpocock opened this issue May 1, 2021 · 13 comments
Closed

Allow for unimplemented actions/services/guards #32

mattpocock opened this issue May 1, 2021 · 13 comments
Labels
enhancement New feature or request
Milestone

Comments

@mattpocock
Copy link

Sometimes, actions/services/guards are best implemented not in the initial definition of the machine. Sometimes, it's best to leave them unimplemented until you use the machine in your frontend/backend code.

This means that Lucy would need to compile action definitions that aren't imported via use.

@matthewp
Copy link
Collaborator

matthewp commented May 2, 2021

Is there an example of what this would compile to? I haven't seen a XState machine like this I don't think.

@mattpocock
Copy link
Author

const machine = createMachine({
  entry: ['helloWorld'],
});

In normal XState, you don't need to define every action that the machine describes. This is an important tool for leaving the implementation up to the 'consumer' of the machine, and I use it all the time

@matthewp
Copy link
Collaborator

matthewp commented May 3, 2021

Ah and then you define those by extending? Makes sense, think I can add this.

@mattpocock
Copy link
Author

Yeah you can define these when you interpret the machine or run useMachine/useInterpret on it

@matthewp
Copy link
Collaborator

matthewp commented May 4, 2021

I really like this idea. It overcomes one of the awkward things about Lucy at the moment, the interface between Lucy and JavaScript. This idea sidesteps the issue by making Lucy files purely descriptive. I'm wondering if we should maybe even encourage this pattern over importing JS. Will see how it looks once it's done.

@mattpocock
Copy link
Author

mattpocock commented May 4, 2021

@matthewp I 100% agree. I also think Lucy would benefit from not exporting a machine, but exporting a createMachine function. I.e:

import createToggleMachine from './toggle.lucy';

interface Context {}

type Event = { type: "EVENT" }

const machine = createToggleMachine<Context, Event>({ actions: {}, services: {} });

This is both more flexible in terms of Typescript (allows for generics) and provides first-class typings for actions/services/guards etc.

EDIT:

And also could make Lucy's syntax a lot simpler by removing/discouraging the use of 'use'.

@matthewp
Copy link
Collaborator

matthewp commented May 4, 2021

@oliverturner curious to hear your thoughts on this, if you have any.

@matthewp
Copy link
Collaborator

matthewp commented May 5, 2021

@mattpocock Can you open a separate issue to discuss your idea for changing what gets exported? I'm intrigued by the idea but want to keep this one focused on allowing unimplemented named guards and actions.

@matthewp matthewp added the enhancement New feature or request label May 5, 2021
@matthewp
Copy link
Collaborator

matthewp commented May 6, 2021

For this issue I'm going to allow you to define a named guard or action without assigning a value like so:

action log
guard isValidCard

state idle {
  purchase => isValidCard => log => purchasing
}

state purchasing {}

In #34 we can talk about what an inline form would look like.

@mattpocock
Copy link
Author

Perfeito

@matthewp matthewp added this to the 0.3.0 milestone May 15, 2021
@reaktivo
Copy link

For this issue I'm going to allow you to define a named guard or action without assigning a value like so:

action log
guard isValidCard

state idle {
  purchase => isValidCard => log => purchasing
}

state purchasing {}

In #34 we can talk about what an inline form would look like.

This is great, I was just about to open an issue for a feature request allowing actions and guards to be injected, instead of imported and this solves the issue neatly

@matthewp
Copy link
Collaborator

@reaktivo you might want to look at #34 where this is better explained. Essentially we are changing machine signatures to be a function that takes in actions/guards, etc. and returns a StateMachine. The :name syntax signifies something that needs to be passed in. So the above example could be either:

action log = :log
guard isValidCard = :isValidCard

state idle {
  purchase => isValidCard => log => purchasing
}

state purchasing {}

Or with an inline form:

state idle {
  purchase => guard(:isValidCard) => action(:log) => purchasing
}

state purchasing {}

@matthewp
Copy link
Collaborator

Closed by #41 41

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants