Subscribe on changes!

Provide/Inject Works Inconsistently with Templates for Reactive Properties

avatar
Jul 26th 2021

Version

3.2.0-beta.5

Reproduction link

https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHRlbXBsYXRlPlxuICA8aDE+PENoaWxkIC8+PC9oMT5cbjwvdGVtcGxhdGU+XG5cbjxzY3JpcHQ+XG5pbXBvcnQgeyBjb21wdXRlZCB9IGZyb20gJ3Z1ZSc7XG5pbXBvcnQgQ2hpbGQgIGZyb20gJy4vY2hpbGQudnVlJ1xuICBcbmV4cG9ydCBkZWZhdWx0IHtcbiAgY29tcG9uZW50czogeyBDaGlsZCB9LFxuICBwcm92aWRlOiB7XG4gICAgdXNlcjogY29tcHV0ZWQoKCkgPT4gJ0ppbScpLFxuICB9LFxufTtcbjwvc2NyaXB0PiIsImNoaWxkLnZ1ZSI6Ijx0ZW1wbGF0ZT5cbiAgPGRpdj5Vc2VyOiB7eyB1c2VyLnZhbHVlIH19PC9kaXY+XG48L3RlbXBsYXRlPlxuXG48c2NyaXB0PlxuZXhwb3J0IGRlZmF1bHQge1xuICBpbmplY3Q6IFsndXNlciddLFxufVxuPC9zY3JpcHQ+In0=

Steps to reproduce

Create a parent component like this one:

<template>...</template>
<script>
import { computed } from 'vue';

export default {
  provide: {
    user: computed(() => 'jim'),
  },
};
</script>

And then create a child component like this one:

<template>
  <div>{{ user.value }}</div>
</template>

<script>
export default {
  inject: ['user'],
}
</script>

What is expected?

I should not need to use .value in the template in order to be consistent with reactivity in the composition API.

What is actually happening?

I am required to use .value when using using computed() to make items reactive with provide/inject, but I don't have to use .value when using computed() with the composition API.


This behavior seems inconsistent. At a minimum, it seems like this inconsistency should receive better treatment in the docs to explain why there's a difference.

avatar
Jul 27th 2021

I think it would make sense to unwrap the injected properties in the template like when they are returned in setup:

export default {
  setup() {
    return {
      user: inject('user')
    }
  }
}
avatar
Jul 27th 2021

if unwrap the injected properties in the template, this may be a breaking change.

avatar
Jul 27th 2021

Given that the setup equivalent works, I would consider it a fix

avatar
Jul 27th 2021

@posva are you suggesting that toDisplayString should always unref any object that is passed to it?

or you saying that using setup is the fix

avatar
Jul 27th 2021

Neither. Using setup is a workaround. In the template, you should only need to write user not user.value in both cases (option and setup api). But I'm only suggesting it and giving one argument for it

avatar
Jul 27th 2021

Having not looked at the code, I don't know if this would be possible (or how difficult), but to avoid a breaking change it could perhaps unwrap the value, but also ignore .value in the template for previously wrapped items if the user provides it in the template for something that is already unwrapped. Might be messy though. If this is possible and not too messy, .value could be marked as deprecated and removed in a future release (which would probably be a breaking change at that point).

avatar
Jul 27th 2021

I agree unwrapping should be the desired behavior for consistency, but indeed this would technically be a breaking change.

I think the middle ground is raising a warning for now and require explicitly opting into the fixed behavior. Then in the next minor we will default to the fixed behavior.