vuejs / rfcs

RFCs for substantial changes / feature additions to Vue core
4.85k stars 551 forks source link

Vue3 inject function should support self-inject #254

Closed huanggm closed 3 years ago

huanggm commented 3 years ago

Summary

Vue3 inject function should support self-inject.

Links

CyberAP commented 3 years ago

The alternative here is to work with the order of your provide and inject.

inject('foo') // ancestor-inject

provide('foo', 'bar')
provide('foo', 'bar')

inject('foo') // self-inject

Or just use a reference?

const provision = 'bar'

provide('foo', provision)

// work with the `provision` reference

That of course is not supported for Options API and I think it would benefit the most from this change (though it is not covered in the proposal).

huanggm commented 3 years ago

@CyberAP Thank you for your reply.

In fact. With Vue@3.0.1 we can get different inject type by adjust the order of provide and inject.

Like what you said.

inject('foo') // ancestor-inject
provide('foo', 'bar')

provide('foo', 'bar')
inject('foo') // self-inject

But we cannot get the same result from Vue@3.0.2. The real result is this.

inject('foo') // ancestor-inject
provide('foo', 'bar')

provide('foo', 'bar')
inject('foo') // ancestor-inject

Of course use a reference can solve this problem. Though I think it is a little verbose.

yyx990803 commented 3 years ago

Thanks but this doesn't seem to warrant an additional flag given that within Composition API you should already have a reference to the value provided by the same component.

newcat commented 2 years ago

within Composition API you should already have a reference to the value provided by the same component.

That is true, however, there are use-cases where this is difficult to use / increases complexity quite a bit.

Suppose we have a parent component:

setup() {
  const foo = ref("foo");
  provide("foo", foo);
}

and a use function:

function useFooBar() {
  const foo = inject("foo");
  return { bar: computed(() => foo.value + "bar") };
}

In child components, I can now use useFooBar as expected. But it won't work in the parent component:

setup() {
  const foo = ref("foo");
  provide("foo", foo);
  // doesn't work without self-injecting
  const { bar } = useFooBar();
}

Of course I can provide foo as a parameter to the useFooBar function, but that would mean I need to write the inject("foo") statement into every child component - which is IMHO essentially the opposite of what the Composition was trying to do: decrease complexity by creating small reusable use functions.

iamandrewluca commented 2 years ago

https://github.com/logaretm/vee-validate also has such a use case

const form = useForm()
const field = useField()

It uses a custom inject so useField can inject context of useForm from same component