Vue: Los accesorios proporcionados no se inyectan en componentes funcionales

Creado en 7 jun. 2017  ·  16Comentarios  ·  Fuente: vuejs/vue

Versión

2.3.3

Enlace de reproducción

http://jsfiddle.net/p861bj9y/

pasos para reproducir

Creé una reproducción mínima del comportamiento que estoy tratando de probar, el ejemplo solo necesita JSX para funcionar.

¿Lo que es esperado?

Las propiedades transmitidas por el padre deben aparecer en ctx.injections .

¿Qué está pasando realmente?

Ctx.injections existe pero permanece vacío. Las propiedades no se transmiten al contexto del componente funcional.

bug

Comentario más útil

¿Hay planes para solucionar este problema en la versión 3?

Por ejemplo, estoy tratando de abstraer un v-for en una función de renderizado, pero mis hijos pueden ser componentes funcionales (por lo que ya están renderizados al entrar en la función de renderizado y no puedo clonarlos).

Todos 16 comentarios

Es porque en lugar de parent , child se consideran hijos de vm (tal vez un problema). Por lo tanto, es posible que deba escribir provide en vm .

Por cierto, tu violín está usando [email protected] 😅

El algoritmo de búsqueda para proporcionar inyección es que el niño se mira a sí mismo en busca de los atributos proporcionados y luego recorre su jerarquía $parent en busca de los accesorios proporcionados hasta que está en la raíz.
https://github.com/vuejs/vue/blob/b182ac40697edbe8253d4bd68b6ac09e93259e1c/src/core/instance/inject.js#L59 -L59

No se pudo ejecutar el violín, pero cuando ejecuté https://jsfiddle.net/Austio/vhgztp59/7/ este violín, el $ parent no estaba definido en el componente secundario cuando llegué al contexto de búsqueda. Al menos eso es un comienzo si esto no es un problema con el renderizado en ranuras y no existe una relación entre los componentes.

parece que el componente funcional se renderiza antes de que se resuelvan las ranuras

@Kingwl correcto, y eso es una especie de requisito técnico.

Recuerdo que planteé el tema porque me estaba volviendo loco. Al final, me pareció normal porque los componentes funcionales están conectados al componente en el que se representan y, por lo tanto, cuando se usan en una ranura, se adjuntan al componente exterior. Sin embargo, este no es el caso de los componentes no funcionales:

El contenedor inyecta mode: 'foo' y renderiza <div><slot/></div>

<!-- rendered in App -->
<container>
   <!-- parent is App, mode is undefined -->
  <functional></functional>
</container>

<container>
   <!-- parent is container, mode is foo -->
  <not-functional></not-functional>
</container>

http://jsfiddle.net/p861bj9y/

editar: @alidcastano Actualicé el violín en tu comentario ya que el tuyo ni siquiera estaba usando Vue 2

Jaja, lo siento por usar la versión incorrecta de Vue en el violín, estaba demasiado atrapado por no poder configurar JSX que no me di cuenta. @posva ¡ Gracias por arreglar mi ejemplo!

-

Entonces, el problema aquí no es que el componente funcional no pueda recibir las propiedades proporcionadas, ¿es que el componente funcional se representa antes que la ranura?

@LinusBorg Por "requisito técnico", ¿significa eso que no hay solución o que el comportamiento es intencionado?

¿Debería crearse un contenedor para que sirva como vm que transmite los accesorios? Por ejemplo, el diseño cambiaría a esto:

// before
<parent-component>
  <child-component />
</parent-component>

// after
<vm-container>
   <parent-component>
     <child-component />
   </parent-component>
<vm-container>

Pero el ejemplo anterior parece innecesariamente inflado, ya que la esencia del componente principal ya incluía todos los datos que necesitaba proporcionar al niño. Pero estoy abierto a la discusión; ¿Es esto lo que sugieres?

el vm-container no cambiará nada porque la ranura se representa en el contexto app

Por "requisito técnico", ¿significa eso que no hay una solución alternativa o que el comportamiento es intencionado?

El comportamiento es el resultado de la forma en que funcionan los componentes funcionales. Considere este conjunto de componentes:

<!-- template of a `parent` component -->
<template>
  <Child>
    <functional />
  </Child>
</template>

Cuando pasa un componente funcional a la ranura de otro componente, debe renderizarse antes de pasarlo al hijo, de modo que ese componente hijo pueda recibir los vNodes resultantes como contenido de la ranura. (*)

En el contexto de mi ejemplo anterior, eso significa que en el momento en que se procesa el componente <functional> , el elemento primario disponible es el componente externo ( <parent> ), no el <child> .

En consecuencia, las únicas inyecciones disponibles para el componente funcional son las que también están disponibles en <parent> .


(*): Así es como funciona la implementación actual del virtualdom con componentes funcionales. Cambiar eso requeriría cambiar bastante la mecánica interna.

@posva @LinusBorg Entendido , gracias por explicarme.

Entonces, debido a estos requisitos, la única forma de utilizar provide / inject con componentes funcionales es que los accesorios se proporcionen en el contexto app .

Estoy seguro de que esta restricción se aclarará en la documentación. Continúe y cierre este problema si no hay nada más que deba hacerse o aclararse; ¡gracias de nuevo!

Tal vez podamos encontrar una manera de mejorar el componente funcional en la ranura.
Pero por el momento, debería hacerse como dijeron @posva y @LinusBorg

@Kingwl Gracias por mantener esto abierto.

Finalmente tuve algo de tiempo para intentar incorporar esto en mi complemento vue-mobiledoc-editor siguiendo los consejos anteriores. Un problema que preveo si el componente debe usarse desde la instancia app , es que es más difícil permitir flexibilidad con los componentes anidados utilizados.

Por ejemplo, tengo que exportar los componentes ya registrados en la instancia de la aplicación:

...

export default Vue.extend({
  render (h) {
    return (
      <div>
        <ParentComp>
          <ChildFuncComp/>
        </ParentComp>
      </div>
    )
  },

  provide () { // data that needs to be injected into functional components 
    return {
       msg: 'hello'
    }
  },

  components: {
    ParentComp,
    ChildFuncComp
  }
})

Entonces, según tengo entendido, cuando el usuario está usando el complemento, sería así:

// template
<div id="app">
   <div id="#someWhereInApp" />
</div>

// script 
import SuperCoolComponent from 'SuperCoolComponent' 

export default {
   mounted () {
    this.$once('mounted', () => new SuperCoolComponent().$mount('#someWhereInApp'))
    this.$emit('mounted')
  }
}

Si mi implementación es correcta, esto limita severamente el uso de proporcionar / inyectar componentes funcionales, ya que no se le permite importar y registrar individualmente los componentes que desea utilizar.

En su lugar, usaría componentes completos para admitir el suministro / inyección

estoy tratando de resolver esto
tal vez sea un proceso largo🌚

@Kingwl ¿

¿Hay planes para solucionar este problema en la versión 3?

Por ejemplo, estoy tratando de abstraer un v-for en una función de renderizado, pero mis hijos pueden ser componentes funcionales (por lo que ya están renderizados al entrar en la función de renderizado y no puedo clonarlos).

¿Cualquier actualización?

¿Fue útil esta página
0 / 5 - 0 calificaciones