Computed values #2384
Replies: 9 comments 11 replies
-
Is there any way we could achieve the syntactic simplicity of |
Beta Was this translation helpful? Give feedback.
-
Its very cool to see what
|
Beta Was this translation helpful? Give feedback.
-
Why would an overridden action not have access to the computed properties? As long a you import the model you can use the property right? (I may be misunderstanding)
Yeah, without caching, what are we getting here by defining these properties on the model that couldn't be done with simple functions that take a context? |
Beta Was this translation helpful? Give feedback.
-
Really excited for this. Just curious but can computed properties also be added to import * as X from "xstate"
export default {
actions: {},
computed: {},
activities: {},
services: {},
guards: {}
} An extra var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// a computed getter
reversedMessage: function () {
// `this` points to the vm instance
return this.message.split('').reverse().join('')
}
}
}) |
Beta Was this translation helpful? Give feedback.
-
Tangentially related thought.. Might be nice to have a In some cases that could end up a lot neater than having to have a bunch parallel states for simple things like "has the user selected anything" etc. just to control the behavior of a single action. It would instead be |
Beta Was this translation helpful? Give feedback.
-
Would it be a good idea for Then you could just do |
Beta Was this translation helpful? Give feedback.
-
Glad to see this being discussed. It prompted me to put down some ideas I had. I've created a new discussion so as not to divert this one - #2399 |
Beta Was this translation helpful? Give feedback.
-
I was looking at the concept of computed values in #2384. I love it - have plenty of use cases for that to further clean up code. I'm curious if there are any ways to "return" data from a machine. This would make machines more capable of being data stores (in my use cases). Instead of sending an event and then using the context value, I may want to have computed/getter methods to pick what I want. This is different from a selector because it involves additional data and might be used in multiple places at once. I'll use a contrived example because I can't share business specifics. Let's say I have a store of user profiles. Then I have a comments machine. If I want to display the user's name and profile image next to each of their comments, I need to create a function like: export function getUser(context, userId) {
return context.list.find(user => user.id === userId);
} and then use it: <Comment :user="getUser(userState.context, comment.userId)" /> My hope would be able to do: export function getUser(context, userId) {
return context.list.find(user => user.id === userId);
}
export const usersMachine = createMachine({
id: 'users',
// ...
},
{
computed: {
byId: (context, /* args */ { userId }) => context.list.find(user => user.id === userId),
},
}); and then use it like: <Comment :user="userState.computed.byId(comment.userId)" /> I know an overarching goal of this project (and many others) is to stay lean and not include unnecessary features. This is just what seems like a nice thing to have if this proposal was implemented. |
Beta Was this translation helpful? Give feedback.
-
I wanted to add my two cents as I love the idea of computed properties and how I've been operating at work with the idea of ViewModel and leveraging NgRx ComponentStore ComponentStore is based around the idea of a Subject in a service, where you'd have a Subject to contain your state for a component and All of this to say it's really easy to create computed views of your data with the ComponentStore selectors. For example interface MyState {
firstName: string,
lastName: string,
}
export class MyStore extends ComponentStore<MyState> {
// select "slices" from the stores state
readonly firstName$ = this.select(state => state.firstName)
readonly lastName$ = this.select(state => state.lastName)
// create a computed view model by selecting from streams and projecting it into a new object
readonly viewModel$ = this.select(
this.firstName$,
this.lastName$,
(first, last) => {
return {
fullName: `${first} ${last}`,
username: `${first}.${last}`
}
}, {debouce: true}) // let changes "settle" to not emit too frequently helps when you have a "large" view model
constructor() {
super({firstName: 'barbados', lastName: 'clemens'}) // this is your initial state.
}
readonly setFirstName = this.update<string>((state, value) => ({...state, firstName: value})) // this is like a normal reducer function!
// run side effect like contacting the API or calling other effects
// you can also update the state in an effect with this.patchState({})
readonly saveChanges = this.effect(trigger$ => trigger$
.pipe(
withLatestFrom(this.firstName, this.lastName), // grab from our selectors above
exhaustMap(([, first, last]) => this.someService.callMyApi({first,last}) // run a side effect
)) The most important part is the the state is frozen in the component store so in order to update it you have to run through updaters/effects to patch or replace the entire state object. these updaters/effects can take in a single value like All of this to say I think computed: {
fullName: state => state.context.firstName + state.context.lastName
} makes the most sense to me, but if you're only going to use the context to create the computed values, then context: {
fullName: createComputed(context => context.firstName + ' ' + context.lastName),
} could make sense. @nartc might have more opinions on it as he has worked with ComponentStore and just started toying with XState, and I generally just want to know what they'd think of how using computed properties might look in state. A walk-through of ComponentStore and its usage patterns can be found from this youtube series. |
Beta Was this translation helpful? Give feedback.
-
This RFC proposes adding a computed values feature to XState models via
createModel(...)
:Thoughts? Suggestions?
Prior art:
Beta Was this translation helpful? Give feedback.
All reactions