Vue: Les accessoires fournis ne sont pas injectés dans les composants fonctionnels

Créé le 7 juin 2017  ·  16Commentaires  ·  Source: vuejs/vue

Version

2.3.3

Lien de reproduction

http://jsfiddle.net/p861bj9y/

Étapes à suivre pour reproduire

J'ai créé une reproduction minimale du comportement que j'essaie de tester, l'exemple a juste besoin de JSX pour fonctionner.

Qu'attend-on?

Les propriétés transmises par le parent doivent apparaître dans ctx.injections .

Que se passe-t-il réellement?

Ctx.injections existe mais reste vide. Les propriétés ne sont pas transmises au contexte du composant fonctionnel.

bug

Commentaire le plus utile

Est-il prévu de résoudre ce problème dans la v3?

Par exemple, j'essaie d'abstraire un v-for dans une fonction de rendu, mais mes fils peuvent être des composants fonctionnels (ils sont donc déjà rendus lors de la saisie de la fonction de rendu et je ne peux pas les cloner).

Tous les 16 commentaires

C'est parce qu'au lieu de parent , child est considéré comme des enfants de vm (peut-être un problème). Vous devrez peut-être écrire provide dans vm .

BTW, votre violon utilise [email protected] 😅

L'algorithme de recherche pour fournir inject est que l'enfant recherche lui-même les attributs fournis, puis boucle sa hiérarchie $parent à la recherche des accessoires fournis jusqu'à ce qu'il soit à la racine.
https://github.com/vuejs/vue/blob/b182ac40697edbe8253d4bd68b6ac09e93259e1c/src/core/instance/inject.js#L59 -L59

Impossible de faire fonctionner votre violon, mais lorsque j'ai exécuté https://jsfiddle.net/Austio/vhgztp59/7/ ce violon, le $ parent n'était pas défini sur le composant enfant lorsque je suis arrivé au contexte de recherche. Au moins, c'est un début si ce n'est pas un problème de rendu dans les emplacements et qu'il n'y a pas de relation entre les composants.

il semble que le composant fonctionnel soit rendu avant la résolution des emplacements

@Kingwl est correct, et c'est une sorte d'exigence technique.

Je me souviens que j'ai soulevé ce point parce que j'en devenais fou. À la fin, cela m'a semblé normal car les composants fonctionnels sont attachés au composant dans lequel ils sont rendus et donc lorsqu'ils sont utilisés dans un slot, ils sont attachés au composant externe. Cependant, ce n'est pas le cas des composants non fonctionnels:

Le conteneur injecte mode: 'foo' et affiche <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/

edit: @alidcastano J'ai mis à jour le violon dans votre commentaire car le vôtre n'utilisait même pas Vue 2

Haha désolé d'avoir utilisé la mauvaise version de Vue dans le violon, j'étais trop pris de ne pas pouvoir configurer JSX que je ne réalisais pas. @posva Merci d'avoir

-

Le problème ici n'est donc pas que le composant fonctionnel ne peut pas recevoir les propriétés fournies, c'est que le composant fonctionnel est rendu avant le slot?

@LinusBorg Par "exigence technique", cela signifie-t-il qu'il n'y a pas de solution de contournement ou que le comportement est voulu?

Un conteneur devrait-il être créé pour servir de vm qui transmet les accessoires? Par exemple, la conception changerait en ceci:

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

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

Mais l'exemple ci-dessus semble inutilement gonflé puisque l'essence du composant parent comportait déjà toutes les données qu'il avait besoin de fournir à l'enfant. Mais je suis ouvert à la discussion; est-ce ce que vous suggérez?

le vm-container ne changera rien car le slot est rendu dans le contexte app

Par «exigence technique», cela signifie-t-il qu'il n'y a pas de solution de contournement ou que le comportement est voulu?

Le comportement est le résultat du fonctionnement des composants fonctionnels. Considérez cet ensemble de composants:

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

Lorsque vous passez un composant fonctionnel dans l'emplacement d'un autre composant, il doit être rendu avant d'être transmis à l'enfant, afin que ce composant enfant puisse recevoir les vNodes résultants en tant que contenu de l'emplacement. (*)

Dans le contexte de mon exemple ci-dessus, cela signifie qu'au moment où le composant <functional> est rendu, le parent disponible est le composant externe ( <parent> ), pas le <child> .

Par conséquent, les seules injections disponibles pour le composant fonctionnel sont celles qui sont également disponibles dans <parent> .


(*): C'est ainsi que l'implémentation actuelle du domaine virtuel fonctionne avec des composants fonctionnels. Pour changer cela, il faudrait changer beaucoup de mécanismes internes.

@posva @LinusBorg J'ai

Donc, en raison de ces exigences, la seule façon d'utiliser fournir / injecter des composants fonctionnels est d'avoir les accessoires fournis dans le contexte app .

Je suis sûr que cette contrainte sera clarifiée dans la documentation. Veuillez continuer et fermer ce problème s'il n'y a rien d'autre à faire ou à clarifier; Merci encore!

Peut-être pouvons-nous trouver un moyen d'améliorer le composant fonctionnel dans la fente
Mais pour le moment, cela devrait être fait comme @posva et @LinusBorg l'ont dit

@Kingwl Merci de garder cela ouvert.

J'ai enfin eu le temps d'essayer d'intégrer cela dans mon plugin vue-mobiledoc-editor en utilisant les conseils ci-dessus. Un problème que je prévois si le composant doit être utilisé à partir de l'instance app , est qu'il est plus difficile de permettre la flexibilité avec les composants imbriqués utilisés.

Par exemple, je dois exporter les composants déjà enregistrés sous l'instance d'application:

...

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
  }
})

Ensuite, d'après ce que j'ai compris, lorsque l'utilisateur utilise le plugin, ce serait comme ceci:

// 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 mon implémentation est correcte, cela limite considérablement l'utilisation de fournir / injecter des composants fonctionnels, car vous n'êtes pas autorisé à importer et à enregistrer individuellement les composants que vous souhaitez utiliser.

J'utiliserais plutôt des composants complets pour prendre en charge fournir / injecter

j'essaye de résoudre ça
peut-être que c'est un long processus🌚

@Kingwl Avez-vous pu le résoudre?

Est-il prévu de résoudre ce problème dans la v3?

Par exemple, j'essaie d'abstraire un v-for dans une fonction de rendu, mais mes fils peuvent être des composants fonctionnels (ils sont donc déjà rendus lors de la saisie de la fonction de rendu et je ne peux pas les cloner).

Toute mise à jour?

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

julianxhokaxhiu picture julianxhokaxhiu  ·  3Commentaires

seemsindie picture seemsindie  ·  3Commentaires

lmnsg picture lmnsg  ·  3Commentaires

bfis picture bfis  ·  3Commentaires

robertleeplummerjr picture robertleeplummerjr  ·  3Commentaires