刷刷题9

380 阅读8分钟

pinia与vuex的区别

Vuex 和 Pinia 都是用于 Vue 应用程序的状态管理库,它们有一些相似之处,但也存在一些差异。以下是它们的对比:

一、相似之处

  1. 集中式状态管理

    • 两者都提供了一种集中式的方式来管理应用程序的状态。这使得状态可以在不同的组件之间共享,并且可以更容易地跟踪和调试状态的变化。
    • 例如,在一个电商应用中,用户的购物车状态可以存储在状态管理库中,以便在不同的页面和组件中访问和更新。
  2. 响应式状态

    • Vuex 和 Pinia 都与 Vue 的响应式系统集成,使得状态的变化可以自动触发相关组件的重新渲染。

    • 当购物车中的商品数量发生变化时,相关的组件可以自动更新以反映这个变化。

二、不同之处

  1. 语法和 API

    • Pinia

      • Pinia 提供了一种更加简洁和直观的 API。它使用类似于 Vue 组件的语法来定义状态和操作,使得代码更加易读和易于维护。
      • 例如,定义一个 store 可以像这样:
import { defineStore } from "pinia";

export const useCartStore = defineStore("cart", {
  state: () => ({
    items: [],
  }),
  actions: {
    addItem(item) {
      this.items.push(item);
    },
  },
});

Vuex

  • Vuex 的语法相对较为复杂,需要定义 mutations、actions 和 getters 等不同的概念来管理状态。
  • 例如,定义一个 store 可能如下所示:
import Vuex from "vuex";

const store = new Vuex.Store({
  state: {
    items: [],
  },
  mutations: {
    ADD_ITEM(state, item) {
      state.items.push(item);
    },
  },
  actions: {
    addItem({ commit }, item) {
      commit("ADD_ITEM", item);
    },
  },
  getters: {
    cartItems: (state) => state.items,
  },
});

  • inia 的模块系统更加灵活和易于使用。可以轻松地将 store 拆分为多个模块,并且可以在不同的模块之间共享状态和操作。
  • 例如,可以创建一个名为user的模块和一个名为cart的模块,并在它们之间共享一些状态和操作:''
import { defineStore } from "pinia";

const useUserStore = defineStore("user", {
  //...
});

const useCartStore = defineStore("cart", {
  state: () => ({
    //...
  }),
  actions: {
    addItem(item) {
      // 可以访问 userStore 的状态
      if (useUserStore().isLoggedIn) {
        //...
      }
    },
  },
});

类型支持

  • Pinia

    • Pinia 对 TypeScript 的支持非常好,可以轻松地为 store 定义类型,并且在开发过程中可以获得更好的类型提示和错误检查。

vue 全局注册组件很方便,为何不都是用全局注册

Vue 的全局注册组件确实提供了便利,特别是在组件需要跨多个视图或组件重复使用时。但是,如果全部或大量使用全局注册,也会带来一些缺点或问题。下面列举了几个不推荐全面使用全局注册组件的原因:

1. 应用启动性能

全局注册的组件会在应用启动时全部加载和注册,这对于小至中等规模的应用可能不是问题。但对于大型或超大型的应用,过多的全局注册会增加应用的启动时间和初始加载时间,对性能造成影响。

2. 代码分割和懒加载

如果使用全局注册,就很难对组件进行代码分割和懒加载,这意味着即使用户当前不需要该组件,它们仍然会被加载。相反,局部注册组件可以结合 Vue 的动态组件和 Webpack 的代码分割特性,按需加载组件,减少首屏加载时间。

3. 命名空间问题

全局注册所有组件可能会导致组件命名冲突。在大型项目中,维护一个不冲突的全局命名空间会变得非常困难。局部注册可以在组件内解决名称冲突,更加灵活。

4. 项目可维护性

使用全局注册,开发者可能难以追踪某个组件的使用情况,因为它可以在任何地方被引用。相比之下,局部注册组件会在使用它的组件文件中明显显示出来,这使得项目结构更清晰,便于团队成员理解和维护。

vue3 里面 <script setup> 作用是啥

在 Vue 3 中,<script setup> 是一种新的组件编写方式,旨在使组件的编写更为简洁明了。它是 Composition API 的一个语法糖,提供了一种更为简洁和易用的方式来定义组件。使用 <script setup> 可以带来几个主要好处:

1. 更简洁的代码

通过 <script setup>,你可以直接在 <script> 标签内使用 Composition API(如 ref, reactive, computed, watch, 等),而无需明确地定义 setup() 函数。这减少了引导性的样板代码,使得组件的逻辑更加紧凑和易读。

2. 更好的类型推断

对于使用 TypeScript 的项目,<script setup> 提供了更好的类型推断支持。在 <script setup> 中声明的变量和函数会自动被视为组件的一部分,使得类型推断更为直接和准确。

3. 易于使用 Composition API 特性

使用 <script setup>,所有顶级的绑定(如变量、函数等)都自动认为是组件的一部分,并且可以在模板中直接使用,无需返回对象。

4. 简化 Props 和 Emits 定义

<script setup> 提供了特殊的编译时 definePropsdefineEmits 函数,允许你以更声明式的方式定义组件的 props 和 emits,同时也提供了类型推断的好处。

示例

为了展示 <script setup> 如何使 Vue 3 组件代码更加简洁,让我们对比传统的 Composition API 用法和使用 <script setup> 语法的用法。

使用传统 Composition API 的组件

<template>
  <button @click="increment">{{ count }}</button>
</template>

<script>
  import { ref, defineComponent } from "vue";

  export default defineComponent({
    setup() {
      const count = ref(0);

      function increment() {
        count.value++;
      }

      return { count, increment };
    },
  });
</script>

在这个例子中,我们首先需要从 vue 导入 ref 和 defineComponent。然后,我们通过 defineComponent 函数定义组件,并在 setup 函数中定义响应式状态和函数,最后返回这些响应式状态和函数以在模板中使用它们。

使用 <script setup> 的组件

<template>
  <button @click="increment">{{ count }}</button>
</template>

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

  const count = ref(0);

  function increment() {
    count.value++;
  }
</script>

当使用 <script setup> 时,我们不需要使用 defineComponent 来定义组件或在 setup 函数中返回响应式状态和方法。相反,我们可以直接定义响应式状态和函数,这些都会自动被视为组件的一部分,并且可以在模板中直接使用。

localStorage 是同步还是异步

在大多数现代浏览器中,localStorage的操作是同步的。

当你使用localStorage.setItem()来存储数据或者localStorage.getItem()来获取数据时,这些操作会立即执行并且不会返回一个 Promise 或者使用回调函数来处理异步操作。

例如:

localStorage.setItem("key", "value");
console.log(localStorage.getItem("key"));

在上面的代码中,设置和获取localStorage中的数据的操作会按顺序立即执行,不会像异步操作那样需要等待一段时间后再执行后续代码。

然而,需要注意的是,虽然localStorage操作本身是同步的,但如果存储的数据量较大,可能会导致性能问题,因为这些操作会阻塞浏览器的主线程。在这种情况下,可能会感觉操作像是异步的,因为浏览器可能会出现卡顿或响应缓慢的情况。

forEach 中和 for 循环 中调用异步函数的区别

在 JavaScript 中,处理异步函数时,for 循环和 forEach 方法之间的行为有显著差异,尤其是当你试图在循环体中使用 async/await 时。理解这些差异对于编写正确且高效的异步代码是很重要的。

使用 forEach 调用异步函数

Array.prototype.forEach 方法用于对数组的每个元素执行一次提供的函数,但它不会等待异步操作完成。换句话说,即便是在 forEach 循环里使用了 async 函数,这个 async 函数依旧会立即执行,但 forEach 不会等待它完成。

const array = [1, 2, 3];

array.forEach(async (item) => {
  await doAsyncOperation(item); // 将立即开始但不会等待完成
});

console.log("Finished"); // 这行代码不会等待上面的异步操作完成就执行

上面的代码中,doAsyncOperation 会对数组中的每个元素立即开始执行,但 forEach 不会等待它们完成。因此,console.log('Finished') 会在所有异步操作完成之前执行。

使用 for 循环调用异步函数

与 forEach 方法不同,for 循环允许在每次迭代时使用 await 关键字等待异步操作的完成。因此,如果你需要按顺序等待每个异步操作完成,for 循环是更好的选择。

const array = [1, 2, 3];

(async () => {
  for (let item of array) {
    await doAsyncOperation(item); // 将等待异步操作完成后再继续下一次迭代
  }

  console.log("Finished"); // 仅在所有异步操作完成后执行
})();

image.png

这里,每个 doAsyncOperation 调用会在下一个开始之前完成。console.log('Finished') 等到所有异步操作完成后才执行,这样就能保证异步操作的完成顺序。

总结

  • 当你不关心异步操作完成的顺序,或不需要等待所有异步操作完成时,可以使用 forEach

  • 如果你需要按顺序等待每个异步操作完成,使用 for 循环(或其他支持 await 的循环,如 for...of 或传统的 for 循环)是一个更好的选择。

  • 一般而言,当涉及到异步函数时,使用 for 循环(允许 await)比 forEach 方法(不等待异步调用完成) 提供了更大的灵活性和控制力。