-
Notifications
You must be signed in to change notification settings - Fork 546
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dynamic Lifecycle Injection #23
Conversation
In the Data Fetching example: const res = value({
status: 'pending',
data: null,
error: null
}) could we use const res = state({
status: 'pending',
data: null,
error: null
}) |
Yes, that would work as well. |
Is there any reason to use one over the other, in this case? |
No, except to demonstrate that refs work in this context as well, I guess. They are the new concept, while |
I love the verbosity in the later examples where custom logic was extracted to their own variables. These have an easy to read/understand intuitive API in my opinion. I hadn't seen it explicitly mentioned in the docs, but can there be many of these variables in a single data component method? (I'm assuming so, but just double checking, I'll bet I missed something) |
Yes, that's possible, and kind of the point. This allows us to pass state from one of these functions to another, which is something that was not really/cleanly possible before with mixins. (silly example incoming:) data() {
const { x, y } = useMousePosition()
const showSideBar = computed(() => x.value < 10)
return {
x,
y,
showSideBar,
}
} |
Are there any intentions to deprecate mixins on version 3? I think that the new Advanced Reactivity API along with this proposal are enough for building reusable bits of logic (and besides, we have renderless components and higher-order components if for some reason this is not enough) without the usual drawbacks of mixins (implicit and hard to follow population of state values in |
It's being discussed, yes. But nothing final. We obviously won't remove mixins in v3, to ensure backwards compatibility in this regard, but personally i think we can drop them in v4. |
Data fetching example is great; can’t wait for this! @LinusBorg, looking at your example above, you pass a computed pointer to the returned data object. Would it be a read-only property in the component’s state same as an ordinary computed property? In practice, would you expect react-hooks-like external functions to return read-only computed pointers alongside mutable pointers (or even methods/functions)? If so I’m not sure how clear it would be to quickly tell which data object properties are read-only vs mutable (I don’t mean it’s bad, I only mean it’s less obvious than ordinary getters/computed properties). One other question I had is: what order do these injected lifecycle hooks fire? If I inject onUpdated in the data method and onUpdated in the created method, which onUpdated fires first? Is it FIFO based on component lifecycle? I only see it mattering if there is an immediate side effect to the DOM or some external API. |
Yes.
That's indeed a valid point - if such a helper returns a normal stateful object, a pointer, and a computed pointer, it's not entirely obvious which is which. 🤔
I think we should specificy this, but haven't so far. I would say it should work like mixins would: Mixed-in lifecycle hooks run first (and here order is FIFO, yes), component's own hooks after that. |
Hello there. Will there be some restrictions on an dynamic lifecycle injection usage ? |
I guess that would be something we could with lint rules in solve in eslint-plugin-vue |
@LinusBorg This might not be the right place for this question, so please feel free to point me to the right place to ask. Picking up your dynamic lifecycle injection illustration as the future replacement for mixins:
I see examples of data, computed values and I get how it would work for lifecycle hooks, but how would I handle props and methods? |
Awesome RFC!I'm really excited about seeing the power of hooks being brought to Vue in such native feeling. In the data fetching example, could the computed() function be used inside the "useFetch" func? Instead of this: data() {
return {
postData: useFetch(computed(() => `/api/posts/${this.id}`))
}
} Maybe something like that: function useFetch(endpointFunc) {
const endpointRef = computed(endpointFunc)
// rest of the function
}
const App = {
// ...
data() {
return {
// Now there's no need to call computed() everytime we fetch the api
postData: useFetch(() => `/api/posts/${this.id}`)
}
}
} |
What's the recommended pattern to use this when the injected is dependent on props change? I mean to achieve something like this. watch: {
someUniqueToken(newToken, oldToken) {
// unsubscribe old service
this.XXXunsub && this.XXXunsub();
// get a service instance that related to this token. inst.in/inst.out is a Rx Subject
const inst = getServiceXXX(newToken);
const subscription = inst.out.subscribe(....);
this.XXXunsub = () => subscription.unsubscribe();
this.XXXin = inst.in;
},
XXXin(newSubject, oldSubject) {
// do some logic composition.
},
} |
data() {
const unsub = value(null)
const XXXIn = value(null)
watch(
vm => vm.someUniqueToken,
(newToken, oldToken) => {
unsub.value && unsub.value()
const inst = getServiceXXX(newToken);
const subscription = inst.out.subscribe(....);
unsub.value = () => subscription.unsubscribe();
XXXin.value = inst.in;
},
)
watch(
() => XXXin,
(newSubject, oldSubject) {
// do some logic composition.
}
)
return {
XXXIn
}
} You wouldn't even have to return And could extract all of this beahvour in a function that you import run in useMyRxLogic(propName) {
const unsub = value(null)
const XXXIn = value(null)
watch(
vm => vm[propName],
(newToken, oldToken) => {
unsub.value && unsub.value()
const inst = getServiceXXX(newToken);
const subscription = inst.out.subscribe(....);
unsub.value = () => subscription.unsubscribe();
XXXin.value = inst.in;
},
)
watch(
() => XXXin,
(newSubject, oldSubject) {
// do some logic composition.
}
)
return {
XXXIn,
unsub,
}
} data() {
const { unsub, XXXIn } = useMyRxLogic('someUniqueToken')
return {
myUnSub: unsub, // easy to rename before exposing on the component, so no naming conflicts
in: XXXIn
}
} |
Closing as part of #42. |
Rendered