序文
Propsとは、親コンポーネントが子コンポーネントにパラメータを渡すことを指しますが、vue3のpropsの原理を理解する方法を紹介します。
導入
その原理を理解する前に、vue の仮想ノードとは何か、そのパフォーマンスがどのようなものかを知る必要があります。
- 仮想ノードは大きくコンポーネント型とエレメント型の2種類に分かれますが、もちろんテキスト型など特殊な仮想ノードも存在します。
- 仮想ノードは、type、props、children という 3 つの基本パラメータを受け取ります。
コンポーネントタイプの場合:
type は、基本的なレンダリング関数やセットアップ関数などが含まれるオブジェクトです。
{
render() {
return h() // render函数返回一个虚拟节点
}
setup() {}
}
props は、親コンポーネントから子コンポーネントに渡されるパラメータです。
Children は、親コンポーネントから子コンポーネントに渡されるスロットです。
要素タイプの場合:
- type は現在のノードの要素タイプです (div など)。
- props は、クラスなどの現在のノードの要素属性です。
- Children は、配列である現在のノードの子要素です。配列の内容はコンポーネントまたは要素です。
原理
前提
これに基づいて、互いに親と子である 2 つのコンポーネント、つまり APP コンポーネント (親) と FOO コンポーネント (子) を作成できます。
import { h } from '../h.js';
import { Foo } from './foo.js';
export const App = {
// render 页面元素内容即template
render() {
// 接收一个Foo,并通过h函数创建一个子组件node2
let node2 = h(
Foo,
{
count: 1
},
{}
)
return h(
'div',
{
id: 'root',
},
[
node2 // App接收Foo组件作为其子组件
]
);
},
setup() {
}
};
import { h } from '../h.js';
// 定义一个Foo组件用于验证Props功能
export const Foo = {
// render 页面元素内容即template
render() {
// ui 页面内容
const foo = h(
'div',
{},
'Foo' + this.count
);
return h('div', {}, [foo]);
},
// 第一个参数props,用于父子组件传值
setup(props) {
console.log(props.count); // 打印传入的props值
}
};
上記のコードから、親コンポーネントと子コンポーネントを表す 2 つのファイルがここで作成されていることがわかります。
vue3 のコンパイル プロセスでは、まずコンポーネントを解析し、コンポーネントをpatch 関数に渡し、現在の仮想ノード タイプがコンポーネントであるか要素であるかを判断してから、次のコンパイルを進めます。
上記の親コンポーネント コードでは、Foo の場合、node2 というコンポーネントを作成し、props の位置に count: 1 の props を渡していることがわかります。
let node2 = h(
Foo,
{
count: 1
},
{}
)
vue は各仮想ノードを再帰的に解析するため、最終的にはこの node2 も解析されます。!!!
以下では、このノード 2 を解析するときに何が行われたか、および props の機能を実装する方法について説明します。
コンポーネントインスタンスオブジェクトの作成
コンポーネント タイプの場合は、次のように、コンポーネントの仮想ノードをパラメータとしてcreateComponentInstanceに渡し、コンポーネント インスタンス オブジェクト を作成します。
export function createComponentInstance(vnode) {
const component = {
vnode,
type: vnode.type,
// 先创建一个空的setupState,去暂存组件类型虚拟节点的setup返回值
setupState: {},
// 创建一个props,用来存储组件虚拟节点接收的props,注意:props不允许改变 (props)
props: {},
}
return component
}
vnode を作成するとき、実際には 3 つの基本パラメーター、つまり type、props、children を受け取ることになるからです。
したがって、ここで渡される vnode には props フィールドがあり、この props フィールドは count: 1 (詳細) です。
このステップで、インスタンスと呼ばれるコンポーネント インスタンス オブジェクトを作成するとします。
小道具操作の初期化
インスタンスはvnode を受け取り、コンポーネントの vnode には実際に props が含まれているためです。
initProps操作が実行され、vnode に props が存在する場合、その props はインスタンスの下の props フィールドにマウントされます。
このとき、コンポーネントインスタンスオブジェクトはpropsの値を正常に取得できます。
プロキシ オブジェクトを作成して Props を取得する
コード内でthis.を通じて props の値を取得でき 、props がコンポーネント インスタンス オブジェクトにマウントされていることがわかっているためです。
したがって、プロキシ オブジェクトが作成されます (このオブジェクトは後でバインドを介してレンダー関数および他の場所にマウントされ、 this. は props によって対応する props にマッピングされます)。
instance.proxy = new Proxy({ _: instance }, PublicInstanceProxyHandlers);
const PublicInstanceProxyHandlers = {
get({ _: instance }, key) {
const { setupState, props } = instance
// 如果在传入的props中,则返回的对应的值 (props)
if (hasOwn(props, key)) {
return props[key]
}
}
}
小道具はパラメータとしてセットアップに渡されます
vue3 にはセットアップにこれが含まれていないことがわかっているため、vue3 は props を受け取り、この props を使用して親コンポーネントによって渡された値を取得できます。
次に、props の値をコンポーネント インスタンス オブジェクトにマウントしたので、props をパラメーターとしてセットアップに渡すことができます。
const {setup} = instance.type.setup // 获取setup函数
// 在执行setup的时候将props传入即可
setup(shallowReadonly(instance.props))
したがって、これを使用するときは、props を受け取ることでセットアップ内の値を読み取ることができます。
1 2 3 4 |
|
レンダリングするプロキシをマウントする
仮想ノードを解析するとき、 thisを通じて props の値を取得できるため、実際には setup 関数が最初に実行され、次にレンダリングされます。
そこで、前に作成したプロキシ オブジェクトをバインドを介してレンダー関数にマウントし、これが props の値を正しく取得できることを確認します。
1 |
|
要約する
以上でpropsの原理の説明を終わります。
Props は実際には、親コンポーネントによって子コンポーネントの仮想ノードの Props に挿入されるパラメーターです。
したがって、サブコンポーネントのコンポーネント インスタンス オブジェクトを作成するときに、この props の値を取得して、それをサブコンポーネントのコンポーネント インスタンス オブジェクトにマウントできます。
コンポーネントでプロップを使用する必要がある場合、通常は 2 つの場所がセットアップまたはレンダリングされます。
セットアップでは、コンポーネント インスタンス オブジェクトの props をパラメータとして渡して使用できるようにしますが、props は変更できない値であるため、readonly でラップする必要があることに注意してください。
コンポーネント ページでは、これを通じて props の値を読み取ることができるため、ページをレンダリングして render 関数を呼び出すときに、プロキシ オブジェクトを作成し、このオブジェクトを render 関数にマウントできます。プロキシを介して、対応する props 値を読み取るには