Type reference provision/injection functionality in VueJS
P粉441076405
P粉441076405 2023-09-04 16:34:30
0
1
540
<p>I'm trying to provide a typed ref from a parent component and inject it into the child component. </p> <p>I'm not sure if I understand the VueJS documentation, but this is what I came up with. </p> <pre class="brush:php;toolbar:false;">import type { Ref } from 'vue' import type { InjectionKey } from 'vue' import type DocumentSet from '@/types/DocumentSet' const documentSet = Symbol() as InjectionKey<{ documentSet: Ref<DocumentSet>, update: () => void }> export default documentSet</pre> <p>So, the task is to provide a typed object (in my case a documentSet), and a function that updates it. </p> <p>Now, in the parent component I have this code: </p> <pre class="brush:php;toolbar:false;">import dsKey from '@/injectionKeys/documentSet' import type DocumentSet from '@/types/DocumentSet' ... const documentSet = ref<DocumentSet | null>(null) provide(dsKey, { documentSet, update: () => console.log('update') })</pre> <p>And in the child component I have this code: </p> <pre class="brush:php;toolbar:false;">import dsKey from '@/injectionKeys/documentSet' const ds = inject(dsKey) const documentSet = ds?.documentSet</pre> <p>The problem is, since there is a lot of boilerplate code, I feel like I'm doing something wrong. For example, I can't understand why the ds object should be refactored like this: </p> <pre class="brush:php;toolbar:false;">const { documentSet } = ds</pre> <p>Is it possible to shorten the code instead of writing <code>ds?.documentSet</code>, especially if I'm sure that ds should exist (without it I won't render the child component)</p> <p>If I write <code>const { documentSet } = inject(dsKey)</code>, the following error will appear: </p> <p><code>TS2339: Property 'documentSet' does not exist on type '{ documentSet: Ref ;' Update: () => Invalid; } | Undefined '.</code></p> <p>The idea is because I want to eliminate duplication in child components: </p> <pre class="brush:php;toolbar:false;"><DocumentSetInfo :documentSet="documentSet" /> <DocumentSetMemos :documentSet="documentSet" /> <DocumentSetPrograms :documentSet="documentSet" /> <DocumentSetPetition :documentSet="documentSet" /> <DocumentSetPassRequests :documentSet="documentSet" /> <DocumentSetReport :documentSet="documentSet" /> <DocumentSetReceptionNotices :documentSet="documentSet" /></pre></p>
P粉441076405
P粉441076405

reply all(1)
P粉446800329

You can put this into a composable that provides a function provde that handles provision and a function use* that handles injection:

const CurrentDocumentSetKey = Symbol() as InjectionKey<{
  documentSet: Ref<DocumentSet>,
  update: () => void
}>

export function provideCurrentDocumentSet(documentSet:DocumentSet, update: () => any){
  provide(CurrentDocumentSetKey, {documentSet, update})
}

export useCurrentDocumentSet(){
  const ds = inject(CurrentDocumentSetKey)
  if (!ds) throw new Error('No current DocumentSet provided')
  return ds
}

Now you only need to call provideCurrentDocumentSet() in the parent component, and all child components only need to perform the following operations:

const {documentSet, update} = useCurrentDocumentSet()

You don't even need to export the InjectionKey, and the component doesn't need to know about it. (For example, Vuetify also does this, for example here)

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template