Vue: Os adereços fornecidos não são injetados em componentes funcionais

Criado em 7 jun. 2017  ·  16Comentários  ·  Fonte: vuejs/vue

Versão

2.3.3

Link de reprodução

http://jsfiddle.net/p861bj9y/

Passos para reproduzir

Criei uma reprodução mínima do comportamento que estou tentando testar, o exemplo só precisa do JSX para funcionar.

O que é esperado?

As propriedades transmitidas pelo pai devem aparecer em ctx.injections .

O que realmente está acontecendo?

Ctx.injections existe, mas permanece vazio. As propriedades não estão sendo transmitidas ao contexto do componente funcional.

bug

Comentários muito úteis

Existem planos para resolver esse problema na v3?

Por exemplo, estou tentando abstrair um v-for em uma função de renderização, mas meus filhos podem ser componentes funcionais (portanto, eles já são renderizados ao entrar na função de renderização e não posso cloná-los).

Todos 16 comentários

É porque em vez de parent , child é considerado filho de vm (talvez um problema). Portanto, pode ser necessário escrever provide em vm .

BTW, seu violino está usando [email protected] 😅

O algoritmo de pesquisa para fornecer injetar é que a criança olha para si mesma em busca de atributos fornecidos e, em seguida, faz um loop em sua hierarquia $parent em busca de adereços fornecidos até que esteja na raiz.
https://github.com/vuejs/vue/blob/b182ac40697edbe8253d4bd68b6ac09e93259e1c/src/core/instance/inject.js#L59 -L59

Não foi possível fazer o seu violino funcionar, mas quando eu executei https://jsfiddle.net/Austio/vhgztp59/7/ este violino o $ parent estava indefinido no componente filho quando cheguei ao contexto de pesquisa. Pelo menos isso é um começo, se não for um problema de renderização em slots e de não haver uma relação entre os componentes.

parece que o componente funcional é renderizado antes que os slots sejam resolvidos

@Kingwl correto, e isso é um tipo de requisito técnico.

Lembro que levantei a questão porque estava ficando louco com isso. No final, parecia normal para mim porque os componentes funcionais são anexados ao componente em que são renderizados e, portanto, quando usados ​​em um slot, eles são anexados ao componente externo. No entanto, este não é o caso com componentes não funcionais:

O contêiner injeta mode: 'foo' e 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 Eu atualizei o violino em seu comentário, pois o seu nem estava usando o Vue 2

Haha, desculpe por usar a versão errada do Vue no violino, eu estava muito preocupado em não conseguir configurar o JSX que não percebi. @posva Obrigado por corrigir meu exemplo!

-

Portanto, o problema aqui não é que o componente funcional não pode receber as propriedades fornecidas, mas que o componente funcional é renderizado antes do slot?

@LinusBorg Por "requisito técnico", isso significa que não há solução alternativa ou que o comportamento é intencional?

Deve um contêiner ser criado para servir como vm que passa pelos adereços? Por exemplo, o design mudaria para este:

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

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

Mas o exemplo acima parece desnecessariamente inchado, uma vez que a essência do componente pai já envolvia todos os dados necessários para fornecer ao filho. Mas estou aberto a discussões; é isso que vocês sugerem?

o vm-container não mudará nada porque o slot é renderizado no contexto app

Por "requisito técnico", isso significa que não há solução alternativa ou que o comportamento é intencional?

O comportamento é resultado da maneira como os componentes funcionais funcionam. Considere este conjunto de componentes:

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

Quando você passa um componente funcional para o slot de outro componente, ele deve ser renderizado antes de ser passado para o filho, para que esse componente filho possa receber os vNodes resultantes como o conteúdo do slot. (*)

No contexto do meu exemplo acima, isso significa que no momento em que o componente <functional> é renderizado, o pai disponível é o componente externo ( <parent> ), não o <child> .

Consequentemente, as únicas injeções disponíveis para o componente funcional são aquelas disponíveis em <parent> também.


(*): É assim que a implementação atual do virtualdom funciona com componentes funcionais. Para mudar isso, seria necessário mudar bastante a mecânica interna.

@posva @LinusBorg Entendi, obrigado por explicar.

Portanto, devido a esses requisitos, a única maneira de usar fornecer / injetar componentes funcionais é ter os adereços fornecidos no contexto app .

Tenho certeza de que essa restrição será esclarecida na documentação. Prossiga e feche este problema se não houver mais nada que precise ser feito ou esclarecido; obrigado novamente!

Talvez possamos encontrar uma maneira de melhorar o componente funcional no slot
Mas no momento, deve ser feito como @posva e @LinusBorg disseram

@Kingwl Obrigado por manter isto aberto.

Finalmente tive algum tempo para tentar incorporar isso em meu plug- in app é que é mais difícil permitir flexibilidade com os componentes aninhados usados.

Por exemplo, tenho que exportar os componentes já registrados na instância do aplicativo:

...

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

Então, pelo meu entendimento, quando o usuário está usando o plugin, seria assim:

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

Se minha implementação estiver correta, isso limita severamente o uso de fornecer / injetar componentes funcionais, uma vez que você não tem permissão para importar e registrar individualmente os componentes que deseja usar.

Eu usaria componentes completos em vez de oferecer suporte ao fornecimento / injeção

estou tentando resolver isso
talvez seja um longo processo🌚

@Kingwl Você conseguiu resolver isso?

Existem planos para resolver esse problema na v3?

Por exemplo, estou tentando abstrair um v-for em uma função de renderização, mas meus filhos podem ser componentes funcionais (portanto, eles já são renderizados ao entrar na função de renderização e não posso cloná-los).

Qualquer atualização?

Esta página foi útil?
0 / 5 - 0 avaliações