VueとReactのビュー更新メカニズムの比較

6353 ワード

VueとReactの最も重要な違いは、データ更新の管理方法が異なり、Vueは基本的にgetter/setterに基づいて実現される依存収集/依存更新のサブスクリプションメカニズムであり、ReactはsetStateなどの明示的なトリガ関数呼び出しによってデータを更新することである.Vueの実装方法は、収集に依存することによって、いくつかのデータの更新がどのような場所で再計算が必要なのかを知ることができ、このメカニズムにより、ビューレンダリングを含む計算属性、watchを優雅に実現することができる.Reactはこのような細粒度のメカニズムが欠けているため、パフォーマンスを向上させるために他のスキームが必要になることが多く、PureComponent、ImmutableJS、shouldComponentUpdateフックなどが発生した.
VueとReactはどのようにビューを更新しますか?
  • Vue:this.value = 3
  • のような付与data
  • React: 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がpropsstateの属性の浅い対比を利用して再レンダリングするかどうかを決定するなどの最適化案を導入する必要があります.浅いコントラストの結果が等しい場合、コンポーネントとそのサブコンポーネントは再レンダリングに関与しません.
    転載先:https://juejin.im/post/5c17568a6fb9a04a006eeb92