Vue和React设计思路PK(一)

287 阅读2分钟

Vue2的Options Api和Vue3的Composition Api

一个简单的todo

  • Options Api

<template>
	<div>
    <input type="text" v-model="val" @keyup.enter="addTodo">
    <u>
      <li v-for="todo in todos" :key="todo.id">{{todo.title}}</li>
    </u>
  </div>
</template>
<script>
export default {
  data() {
    return {
      val: "",
      todos: [
        { id: 0, title: "吃饭", done: false },
        { id: 1, title: "睡觉", done: false },
      ],
    };
  },
  methods: {
    addTodo() {
      this.todos.push({
        id: this.todos.length,
        title: this.val,
        done: false,
      });
      this.val = "";
    },
  },
};
</script>

如上code, 我们就用options api 完成了一个简单的todo

  • 优点
  1. 做各式各样的功能时, 理解起来特别简单 data就是数据, method就是操作
  • 缺点
  1. data, methods, computed, watch等, 可维护性差, 会导致上下反复横跳, 解决办法当然可以使用mixins
<script>
	...
  mixins: ['counter', 'mouse', ...]
	...
</script>

mixins的最大缺点就是命名冲突,虽然能解决反复横跳的问题, 但是在大项目中很难维护, 还有this也是一个黑盒, 没办法知道this里面到底有什么, 很难做测试和做类型推导, 这也就是vue2对ts的支持特别不好的原因.

  • Compostion Api

<script>
import { reactive, ref, toRefs } from "vue";
export default {
  setup() {
    let val = ref("");
    let todos = reactive([
      { id: 0, title: "吃饭", done: false },
      { id: 1, title: "睡觉", done: false },
    ]);
    function addTodo() {
      todos.push({
        id: todos.length,
        title: val.value,
        done: false,
      });
      val.value = "";
    }
    return { val, todos, addTodo };
  },
};

如上code, 我们就用composition api 完成了一个简单的todo

  • 缺点
  1. 难看
  2. return 很蛋疼, 如果组件很大, return也会导致上下横跳

做下简化:

<script setup>
import { reactive, ref, toRefs } from "vue";

let val = ref("");
let todos = reactive([
  { id: 0, title: "吃饭", done: false },
  { id: 1, title: "睡觉", done: false },
]);
function addTodo() {
  todos.push({
    id: todos.length,
    title: val.value,
    done: false,
  });
  val.value = "";
}

通过在script标签上加 setup, 来解决代码冗余的问题, 解决return上下横跳, 使代码更加清爽一点

  • 优点
  1. 可以做Tree Shaking, 没有用到computed, 代码build的时候就会删掉vue3里面的computed的代码
  2. 方便组合, 所有的逻辑都是函数, 组合优于继承

组合优于继承

  • 什么叫组合?

用代码来解释, 写一个累加器

// 新建一个useCounter.js 文件

import { ref } from 'vue'

export default function useCounter() {
    let counter = ref(1)
    function addCounter() {
        counter.value += 1
    }
    return { counter, addCounter }
}

App.vue

<template>
  <div>
    <h1 @click="addCounter">{{counter}}</h1>
  </div>
</template>

<script setup>
import useCounter from "./useCounter";
let { counter, addCounter } = useCounter();
</script>

上面的useCounter.js就是一个组合, 上述的todos也可以进行组合

// 新建一个useTodo.js 文件

import { ref, reactive } from 'vue'

export default function useTodo() {
    let val = ref('')
    let todos = reactive([
        { id: 0, title: '吃饭', done: false },
        { id: 1, title: '睡觉', done: false },
    ])
    function addTodo() {
        todos.push({
            id: todos.length,
            title: val.value,
            done: false,
        })
        val.value = ''
    }
    return { val, todos, addTodo }
}


App.vue

<template>
  <div>
    <h1 @click="addCounter">{{counter}}</h1>
    <input type="text" v-model="val" @keyup.enter="addTodo">
    <u>
      <li v-for="todo in todos" :key="todo.id">{{todo.title}}</li>
    </u>
  </div>
</template>

<script setup>
import { reactive, ref, toRefs } from "vue";
import useCounter from "./useCounter";
import useTodo from "./useTodo";

let { counter, addCounter } = useCounter();
let { val, todos, addTodo } = useTodo();
</script>

组合方式的好处就是组件可以任意拆分, 数据流清晰

React Hooks

下面我们使用React 来写一个累加器

import React, { useState } from 'react'
function App() {
    let [counter, setCounter] = useState(0)
    return (
        <div>
            <h1 onClick={() => setCounter(counter + 1)}>{counter}</h1>
        </div>
    )
}

export default App

看到这是不是觉得Composition api 和 react hooks 很像

Vue3的改动是 由options -> composition

React17的改动是由 class -> hooks

vue的composition所受的诟病是说它抄袭hooks, 但是各自的底层实现是千差万别的

hooks是有严格的先后顺序的

Composition 后续是靠的响应式通知(reactive)

react是没有响应式的, 就是vdom, 计算diff

vue是响应式(reactive)+vdom

  • Hooks
import React, { useState } from 'react'
function App() {
  // 这个函数, 每次render都会执行
  // hooks是有严格的执行顺序的, 是有顺序限制的
  // 不可以写在if里
  
  // 错误写法
  if (xx === 1) {
    let [counter, setCounter] = useState(0)
  }
  // 正确写法
    let [counter, setCounter] = useState(0)
    return (
        <div>
            <h1 onClick={() => setCounter(counter + 1)}>{counter}</h1>
        </div>
    )
}

export default App