【问题标题】:Vue3: re-render component - composition APIVue3:重新渲染组件 - 组合 API
【发布时间】:2022-11-09 01:11:21
【问题描述】:

我有一个导航栏组件和一个视图组件。当用户登录时,我希望两个组件都重新渲染。目前只有视图组件重新渲染,导航栏没有。

尝试强制重新渲染:钥匙传递一个“用户”对象,传递一个更新更改的“navKey”计数器。无论如何,我总是得到“[Vue 警告]:无效的监视源:true 监视源只能是 getter/effect 函数、ref、反应对象或这些类型的数组。"

阅读了数十篇指南和文档,并为此花费了数天时间,但我就是不明白我所缺少的。第一个应用程序,感谢您的帮助。

应用程序.vue

    <template>
      <div v-if="appReady" class="min-h-full font-Poppins box-border">
        <Navigation :key="state" />
        <router-view />
      </div>
    </template>
    
    <script>
    import Navigation from "./components/Navigation.vue";
    import { ref, reactive } from "vue";
    import store from "./store/store.js";
    import { useRouter } from "vue-router";
    
    export default {
      components: {
        Navigation,
      },
    
      setup() {
        // Data & variables
        const appReady = ref(null);
        const router = useRouter()
    
        const user = JSON.parse(localStorage.getItem("BJJFocusUser"))
        const state = store.methods.setUser(user)
    
        if (!user) {
          appReady.value = true;
          console.log("No user logged in");
          router.push({ name: "Login" });
        } else {
          store.methods.setUser(user);
          appReady.value = true;
          console.log("User logged in");
          router.push({ name: "ProgressView" });
        }
    
        return { appReady, user, state };
      },
    };
    </script>

导航.vue

    <template>
      <header class="bg-at-light-orange text-white">
        <nav
          class="container py-5 px-4 flex flex-column gap-4 items-center sm:flex-row"
        >
          <div class="flex items-center gap-x-4">
            <img
              class="w-32"
              src="../assets/vector/default-monochrome-white.svg"
              alt="bjj focus logo"
            />
          </div>
          <Slide
          </Slide>
        </nav>
      </header>
    </template>
    
    <script>
    import { logoutUser } from "../services/userService";
    import { useRouter } from "vue-router";
    import { Slide } from "vue3-burger-menu"
    import store from "../store/store"
    
    export default {
        components: {
            Slide
        },
    
        setup() {
          const router = useRouter();
          const user = store.state.user
    
          // Logout function
          const logout = async () => {
            logoutUser();
            store.methods.setUser()
            router.push({ name: "Login" });
          };    
          return { logout, Slide, store, user };
        },
    
    };
    </script>

Store.js

    import { reactive } from "vue";
    
    const state = reactive({
      user: null,
    });
    
    const methods = {
      setUser(payload) {
        state.user = payload ? payload : null;
      },
      getUser() {
        return JSON.stringify(state.user)
      }
    };
    
    export default {
      state,
      methods,
    };

【问题讨论】:

  • 这可能是 XY 问题。在 Vue 中强制重新渲染并不简单的原因是通常不需要它。绑定数据将在视图中更新,而无需卸载组件。如果需要重新渲染来自store 的数据,您很可能只是在滥用它。来自反应对象的属性需要用计算包装,例如 user = computed(() =&gt; store.state.user)
  • 感谢您的评论 - 这就是我的想法:不需要强制重新渲染。我不明白如何正确修复,以便 Vue 自动重新渲染。我相信 computed() 来自选项 API?
  • 计算完全按照上面列出的方式使用。检查vuejs.org/api/reactivity-core.html

标签: vue.js frontend vuejs3


【解决方案1】:

我设法使导航栏重新渲染的方式是:

  1. 将 EventBus(发射器)添加到登录视图
        // Emitter (EventBus) this section emits an event that can be listened to globally
        const emitter = inject('emitter')
        const emitLogin = _ => {
           emitter.emit('userHasLoggedIn', true)
        }
    
    1. 向注销添加另一个 EventBus(发射器)(在我的情况下,它位于导航栏中)
        // Emitter (EventBus) this section emits an event that can be listened to globally
        const emitter = inject('emitter')
        const emitLogout = _ => {
            emitter.emit('userHasLoggedOut', true)
        }
    
    1. 为 App.vue(根 Vue 组件)添加一个监听器和一个 :key,它读取一个变量,当监听器接收到发射器的信号时,该变量会更新
    
        <template>
          <div v-if="appReady" class="min-h-full font-Poppins box-border bg-at-light-orange">
            <Navigation :key="navRerenderKey" />   // **NOTE THE :key HERE**
            <router-view />
          </div>
        </template>
    
        <script>
        export default {
            setup() {
                // Initialize this variable before the functions
                const navRerenderKey = ref(0)
    
                // Listener (EventBus) this section listens to the emitters
                const emitter = inject('emitter')
                emitter.on('userHasLoggedIn', (value) => {
                    navRerenderKey.value += 1
                    console.log("(emitter) Logged In")
                })
                emitter.on('userHasLoggedOut', (value) => {
                    navRerenderKey.value += 1
                    console.log("(emitter) Logged Out")
                })
            }
        }
        </script>
    

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-08-12
    • 2019-06-01
    • 2020-02-13
    • 2021-11-06
    • 2013-08-25
    • 2023-04-11
    • 2011-02-06
    • 2021-06-19
    相关资源
    最近更新 更多