2.3.3
テストしようとしている動作の最小限の再現を作成しました。この例では、JSXが機能する必要があります。
親から渡されたプロパティはctx.injections
表示されます。
Ctx.injections
存在しますが、空のままです。 プロパティは機能コンポーネントコンテキストに渡されていません。
これは、 parent
代わりに、 child
がvm
子と見なされるためです(おそらく問題です)。 したがって、 vm
provide
を書き込む必要がある場合があります。
ところで、あなたのフィドルは[email protected]を使用してい
提供インジェクトのルックアップアルゴリズムは、子が提供された属性を自分自身で探し、ルートになるまで提供された小道具を検索するために$parent
階層をループアップします。
https://github.com/vuejs/vue/blob/b182ac40697edbe8253d4bd68b6ac09e93259e1c/src/core/instance/inject.js#L59 -L59
フィドルを実行できませんでしたが、 https: //jsfiddle.net/Austio/vhgztp59/7/を実行したときに、ルックアップコンテキストに到達したときに、このフィドルが子コンポーネントで未定義でした。 これがスロットへのレンダリングの問題ではなく、コンポーネント間に関係がない場合は、少なくともそれが始まりです。
スロットが解決される前に機能コンポーネントがレンダリングされているようです
@Kingwlは正しいです、そしてそれは一種の技術的要件です。
夢中になっていたのでポイントを上げたのを覚えています。 結局、機能コンポーネントはレンダリングされたコンポーネントにアタッチされているため、スロットで使用すると外側のコンポーネントにアタッチされるため、私には正常に見えました。 ただし、これは機能しないコンポーネントには当てはまりません。
コンテナ注入mode: 'foo'
とレンダリング<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>
編集: @alidcastanoあなたのコメントはVue 2を使用していなかったので、コメントのフィドルを更新しました
ははは、フィドルで間違ったVueバージョンを使用して申し訳ありませんでしたが、気づかなかったJSXを構成できないことに巻き込まれすぎました。 @posva私の例を修正してくれてありがとう!
-
したがって、ここでの問題は、機能コンポーネントが提供されたプロパティを受け取れないということではなく、機能コンポーネントがスロットの前にレンダリングされるということですか?
@LinusBorg 「技術的要件」とは、回避策がないこと、または動作が意図されていることを意味しますか?
小道具を渡すvm
として機能するコンテナを作成する必要がありますか? たとえば、デザインは次のように変更されます。
// before
<parent-component>
<child-component />
</parent-component>
// after
<vm-container>
<parent-component>
<child-component />
</parent-component>
<vm-container>
しかし、親コンポーネントの本質には、子に提供するために必要なすべてのデータがすでに含まれているため、上記の例は不必要に肥大化しているように見えます。 しかし、私は議論を受け入れています。 これはあなたたちが提案するものですか?
スロットはapp
コンテキストでレンダリングされるため、 vm-container
は何も変更しません
「技術的要件」とは、回避策がないこと、または動作が意図されていることを意味しますか?
この動作は、機能コンポーネントの動作方法の結果です。 このコンポーネントのセットを検討してください。
<!-- template of a `parent` component -->
<template>
<Child>
<functional />
</Child>
</template>
機能コンポーネントを別のコンポーネントのスロットに渡す場合、子コンポーネントに渡される前にレンダリングする必要があります。これにより、子コンポーネントは結果のvNodeをスロットコンテンツとして受け取ることができます。 (*)
上記の例のコンテキストでは、 <functional>
コンポーネントがレンダリングされる時点で、使用可能な親は<child>
ではなく、外部コンポーネント( <parent>
)であることを意味します。
したがって、機能コンポーネントで使用できるインジェクションは、 <parent>
でも使用できるインジェクションのみです。
(*):これが、virtualdomの現在の実装が機能コンポーネントでどのように機能するかを示しています。 それを変更するには、かなり多くの内部メカニズムを変更する必要があります。
@posva @LinusBorg了解しました、説明してくれてありがとう。
したがって、これらの要件により、機能コンポーネントで提供/注入を使用する唯一の方法は、 app
コンテキストで小道具を提供することです。
この制約はドキュメントで明確になると確信しています。 他に実行または明確化する必要のあることがない場合は、この問題を閉じてください。 再度、感謝します!
スロット内の機能コンポーネントを改善する方法を見つけることができるかもしれません
しかし、現時点では、 @ posvaと@LinusBorgが言ったように行う必要があります
@Kingwlこれを開いたままにしてくれてありがとう。
私はついに、上記のアドバイスを使用して、これをvue-mobiledoc-editorプラグインに組み込むことを試みる時間がありました。 コンポーネントをapp
インスタンスから使用する必要があるかどうかを予測する問題のひとつは、ネストされたコンポーネントを使用して柔軟性を持たせることがより難しいことです。
たとえば、アプリインスタンスにすでに登録されているコンポーネントをエクスポートする必要があります。
...
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
}
})
次に、私の理解では、ユーザーがプラグインを使用している場合、次のようになります。
// 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')
}
}
私の実装が正しければ、使用したいコンポーネントを個別にインポートして登録することは許可されていないため、機能コンポーネントでの提供/注入の使用が大幅に制限されます。
代わりに、提供/注入をサポートするために完全なコンポーネントを使用します
私はこれを解決しようとしています
多分それは長いプロセスです🌚
@Kingwl解決できましたか?
v3でこの問題に対処する計画はありますか?
たとえば、v-forをレンダリング関数に抽象化しようとしていますが、子は機能コンポーネントである可能性があります(したがって、レンダリング関数に入るときに既にレンダリングされており、クローンを作成できません)。
すべてのアップデート?
最も参考になるコメント
v3でこの問題に対処する計画はありますか?
たとえば、v-forをレンダリング関数に抽象化しようとしていますが、子は機能コンポーネントである可能性があります(したがって、レンダリング関数に入るときに既にレンダリングされており、クローンを作成できません)。