VueとReactのビュー更新メカニズムの比較
6353 ワード
VueとReactの最も重要な違いは、データ更新の管理方法が異なり、Vueは基本的にgetter/setterに基づいて実現される依存収集/依存更新のサブスクリプションメカニズムであり、ReactはsetStateなどの明示的なトリガ関数呼び出しによってデータを更新することである.Vueの実装方法は、収集に依存することによって、いくつかのデータの更新がどのような場所で再計算が必要なのかを知ることができ、このメカニズムにより、ビューレンダリングを含む計算属性、watchを優雅に実現することができる.Reactはこのような細粒度のメカニズムが欠けているため、パフォーマンスを向上させるために他のスキームが必要になることが多く、PureComponent、ImmutableJS、shouldComponentUpdateフックなどが発生した.
VueとReactはどのようにビューを更新しますか? Vue: のような付与data React:
違いは,Vueはコンポーネントデータのvalueフィールドが更新されたことを知っているが,ReactはコンポーネントのStateが変化したことしか知らず,何のデータが変化したのか分からないことである.
Vueのビュー再レンダリング
Vueのサブスクリプションメカニズムは、どのデータが更新されたかだけでなく、このデータが更新された後の現在のコンポーネントおよびサブコンポーネントのビューを再レンダリングする必要があるかどうかを決定します.これは「依存収集」によって実現され、Vueのビューtemplateはrender関数にコンパイルされ、データ(data/props/computed)にgetterが定義され、各コンポーネントのrender関数を呼び出すたびにgetterによって、どのデータがどのコンポーネントのビューに依存し、次にこれらのデータに値を割り当てるとき、つまりsetterが呼び出され、対応するビューで再レンダリングがトリガーされ、コンポーネントに関係なくrender関数を再呼び出す必要がなくなり、コストが削減されます.Vueの著者が作った図を借りる:(push式更新と呼ぶ)
例を挙げると、サブアセンブリChildはprops
コンソール印刷:
ParentコンポーネントとChildコンポーネントの両方のビューにはParentのdata
ケース2:
コンソール印刷:
valueを変更すると、親コンポーネントは再レンダリングされ、子コンポーネントのrender関数はParentコンポーネントのデータ
Reactの再レンダリング
例を見てみましょう.
ビューのデータさえ使用されず、
転載先:https://juejin.im/post/5c17568a6fb9a04a006eeb92
VueとReactはどのようにビューを更新しますか?
this.value = 3
this.setState({value: 3})
違いは,Vueはコンポーネントデータのvalueフィールドが更新されたことを知っているが,ReactはコンポーネントのStateが変化したことしか知らず,何のデータが変化したのか分からないことである.
Vueのビュー再レンダリング
Vueのサブスクリプションメカニズムは、どのデータが更新されたかだけでなく、このデータが更新された後の現在のコンポーネントおよびサブコンポーネントのビューを再レンダリングする必要があるかどうかを決定します.これは「依存収集」によって実現され、Vueのビューtemplateはrender関数にコンパイルされ、データ(data/props/computed)にgetterが定義され、各コンポーネントのrender関数を呼び出すたびにgetterによって、どのデータがどのコンポーネントのビューに依存し、次にこれらのデータに値を割り当てるとき、つまりsetterが呼び出され、対応するビューで再レンダリングがトリガーされ、コンポーネントに関係なくrender関数を再呼び出す必要がなくなり、コストが削減されます.Vueの著者が作った図を借りる:(push式更新と呼ぶ)
例を挙げると、サブアセンブリChildはprops
value
を使用してレンダリングされ、親アセンブリParentはdata value
をpropsとしてサブアセンブリChildに渡し、1秒後にdataを更新する.// Child.vue
<span class="hljs-built_in">export</span> default {
name: <span class="hljs-string">"Child"</span>,
props: [<span class="hljs-string">"value"</span>],
render(h) {
console.log(<span class="hljs-string">"Child render"</span>);
<span class="hljs-built_in">return</span> h(<span class="hljs-string">"div"</span>, this.value);
}
};
// Parent.vue
import Child from "./components/Child";
export default {
data() {
return {
value: 1
};
},
components: { Child },
created() {
setTimeout(() => this.value = 2, 1000);
},
render(h) {
console.log("Parent render");
return h("div", [
h(Child, {
props: { value: this.value }
})
]);
}
};
コンソール印刷:
Parent render
Parent render
//after 1000ms
Child render
Child render
ParentコンポーネントとChildコンポーネントの両方のビューにはParentのdata
value
が使用されているため、value
の値を変更すると、親子コンポーネントは再レンダリングされます.ケース2:
value
をpropsとしてサブアセンブリChildに渡さず、アセンブリ自体のビューにのみ使用します.
// Child.vue
<script>
<span class="hljs-built_in">export</span> default {
name: <span class="hljs-string">"Child"</span>,
props: [<span class="hljs-string">"value"</span>],
render(h) {
console.log(<span class="hljs-string">"Child render"</span>);
<span class="hljs-built_in">return</span> h(<span class="hljs-string">"div"</span>, this.value);
}
};
// Parent.vue
import Child from "./components/Child";
export default {
data() {
return {
value: 1
};
},
components: { Child },
created() {
setTimeout(() => this.value = 2, 1000);
},
render(h) {
console.log("Parent render");
return h("div", [
h(Child),
this.value + ""
]);
}
};
コンソール印刷:
Parent render
Child render
//after 1000ms
Parent render
valueを変更すると、親コンポーネントは再レンダリングされ、子コンポーネントのrender関数はParentコンポーネントのデータ
value
の依存関係を収集していないため、子コンポーネントは再レンダリングされません.Reactの再レンダリング
setState
が呼び出されると、Reactは何のデータが変化したかを気にせず、コンポーネントのshouldComponentUpdate
をトリガし、trueが返されるとrender
を呼び出し、その後、同じ方法ですべてのサブコンポーネントを順次更新し、false
が返されるとrender
のメソッド呼び出しおよびサブコンポーネント更新を阻止する.すなわち、更新ビューの制御権はshouldComponentUpdate
によって把握され、デフォルトでは、この方法はtrue
に戻る.(Vue著者はpull式更新と呼ぶ):例を見てみましょう.
function Child(props) {
console.log("Child render");
return
;
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
value: 1
};
}
componentDidMount() {
setTimeout(() => {
this.setState({
value: 2
});
}, 1000);
}
render() {
console.log("Parent render");
return (
"App">
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(, rootElement);
控制台打印:
Parent render
Child render
Parent render
Child render
ビューのデータさえ使用されず、
setState
を呼び出すコンポーネントとそのサブコンポーネントは再レンダリングされます.コンポーネントやノードが多い場合、データの更新により多くの不要な仮想DOMが構築され、膨大なノードツリーもdiffの速度を遅らせる可能性があります.この場合、PureComponentがImutableJSに合わせて、PureComponentがprops
とstate
の属性の浅い対比を利用して再レンダリングするかどうかを決定するなどの最適化案を導入する必要があります.浅いコントラストの結果が等しい場合、コンポーネントとそのサブコンポーネントは再レンダリングに関与しません.転載先:https://juejin.im/post/5c17568a6fb9a04a006eeb92