Subscribe on changes!

`Inject()` 3rd argument default value is not `true`

avatar
Jun 28th 2022

Vue version

latest

Link to minimal reproduction

https://sfc.vuejs.org/#eNp9kMFugzAMhl/FyoVWgkTbbqhF2nvkQpnpQMWJbNNNqnj3mcFh2qTdYuf3ly9+uNec/X1GV7uTdDxkBUGdcxNpmHJihUckgIFG7DTSAj2nCQqbKCJF6hKJQgvnPXEoFEWLEg5HODfw9PxyXGMhwC1dAT+zZQQ0AdsjTGughMusey2G6mfqdEjkN3q6obfZQ2ugU9gUG1e6za6a2uxHSWT+36Jxv5Do6k197ZnuWkf3rpqlDkH6bv31KD7xNdjJ80w6TOhRpurC6UOQDRxd+YMRrHlHrhjpDRn5P+av6B/uil1soW75ArNvhdE=

Steps to reproduce

API: Composition - Inject()

Issue: Inject() 3rd argument default value is not true. However, the API Docs type description says true.

It is implemented with very simple code. Just open the playground and check the console log in developer tools.

What is expected?

Inject() expects third argument default value is true.

What is actually happening?

Inject() expects third argument default value is false.

System Info

It was run with the latest version on the playground. This is an issue independent of the runtime environment.

Any additional comments?

During the production of the Vue3 Korean document, I found it during the verification stage of the example code.

This can be confusing for many novice developers.

First, I submitted an issue to vuejs/docs and was told to resubmit here.

avatar
Jun 29th 2022

treatDefaultAsFactory default value is false

image

Examples in the documentation may need to be modified. image

avatar
Jun 29th 2022

I think so too. So I opened an issue in vuejs/docs. However, the member told me to report the issue here as it is not a document issue.

I just hope this problem gets resolved quickly.

avatar
Jun 29th 2022

@edison1105 we also have this export:

export function inject<T>(
  key: InjectionKey<T> | string,
  defaultValue: T | (() => T),
  treatDefaultAsFactory: true
): T

see https://github.com/vuejs/core/blob/8edf4b344179d0a8d3c1090ce63f466f4e787976/packages/runtime-core/src/apiInject.ts#L36

Are we sure we always want to treat the third argument as false? I am happy to modify docs but from the user experience position it would be better if we eagerly treated default value as a factory, unless we explicitly disable this behaviour.

avatar
Jun 29th 2022

@edison1105 we also have this export:


export function inject<T>(

  key: InjectionKey<T> | string,

  defaultValue: T | (() => T),

  treatDefaultAsFactory: true

): T

see https://github.com/vuejs/core/blob/8edf4b344179d0a8d3c1090ce63f466f4e787976/packages/runtime-core/src/apiInject.ts#L36

Are we sure we always want to treat the third argument as false? I am happy to modify docs but from the user experience position it would be better if we eagerly treated default value as a factory, unless we explicitly disable this behaviour.

Thanks for your reply. I see that override of inject. But that's for typescript usage, actually the third args is always false. /cc @LinusBorg what do you think?🤔

avatar
Jun 29th 2022

Apart from the question of what Evan's intended behavior was, the main question is: What's the more common usage?

My gut tells me that it's more common to provide a function (and thus need a function as a default was well), than it is to require a factory function for creating the default value.

Mainly because inject() is usually only called only once per component anyway, and in that moment we can create a per-component default just fine without a factors function:

setup () {
  const myInjectedMap = inject('myKey', new Map()) // no factory function needed.
}

Unless I overlooked an obvious use case for factory functions, I'd say they are a real edge case, and the default value for the third argument should therefore be false.

avatar
Jun 30th 2022

@LinusBorg I've seen cases when people use a factory function returning an array or object for a default value, just like they do it for the default prop value. I am not sure whether they need it to be a factory function but it aligns logically with props default so I can see where this comes from.

@yyx990803 it would be nice to have your input on the treatDefaultAsFactory inject argument so we could align documentation to the source code or vice versa 😅

avatar
Jul 6th 2022

edison1105 we also have this export:

export function inject<T>(
  key: InjectionKey<T> | string,
  defaultValue: T | (() => T),
  treatDefaultAsFactory: true
): T

see

https://github.com/vuejs/core/blob/8edf4b344179d0a8d3c1090ce63f466f4e787976/packages/runtime-core/src/apiInject.ts#L36

Are we sure we always want to treat the third argument as false? I am happy to modify docs but from the user experience position it would be better if we eagerly treated default value as a factory, unless we explicitly disable this behaviour.

My two cents, I think this export means that, the 3rd argument treatDefaultAsFactory should always be explicitly passed with true when the 2nd argument is a function, acts like there is no default value for the 3rd argument. "true" here is a literal type which means it should be true and true only, not that you can omit this argument (otherwise it should be written like "treatDefaultAsFactory = true")

So I suggest the second last example in the docs should be changed from const baz = inject('foo', () => new Map()) to const baz = inject('foo', () => new Map(), true)

avatar
Jun 13th 2023

My original line of thought was similar to what @LinusBorg wrote: sing a default value when injecting is relatively uncommon, using a factory function is indeed rare. This is only needed when the user explicitly need a way to avoid unnecessary initialization cost.

Some other aspects:

  • It can be confusing if functions get special treatment by default. It makes more sense to opt-in to the special case.
  • The current behavior has existed for a long time, and adjusting it would be a breaking change.

I have updated the docs via https://github.com/vuejs/docs/commit/79b448d5fc71a910c3ab60ddecc5c55458eb4526 and https://github.com/vuejs/docs/pull/2317.