当前位置: 首页 > 知识库问答 >
问题:

Vuex从状态加载现有表单数据进行编辑

张心水
2023-03-14

我按照本教程尝试学习 Vue,我已经完成了并且它有效,但我正在尝试做出我正在努力的更改。

https://savvyapps.com/blog/definitive-guide-building-web-app-vuejs-firebase

所以有一个“设置”页面,其中有用户配置文件(他们可以编辑他们的名字等)。当“设置”/“配置文件”页面加载时,我希望表单加载他们的存量数据,这样他们就可以修改它并按保存。

它目前作为占位符加载,带有< code >:placeholder = " user profile . name " -我希望它只是用实际值填充表单,而不是作为占位符。

感觉做这件事应该简单得可笑,但却无法优雅地工作。

<template>
  <section id="settings">
    <div class="col1">
      <h3>Settings</h3>
      <p>Update your profile</p>

      <transition name="fade">
        <p v-if="showSuccess" class="success">profile updated</p>
      </transition>

      <form @submit.prevent>
        <label for="name">Name</label>
        <input v-model.trim="name" type="text" id="name" />

        <label for="title">Job Title</label>
        <input v-model.trim="title" type="text" id="title" />

        <button @click="updateProfile()" class="button">Update Profile</button>
      </form>
    </div>
  </section>
</template>

<script>
import { mapState } from "vuex";

export default {
  data() {
    return {
      name: "",
      title: "",
      showSuccess: false,
    };
  },
  computed: {
    ...mapState(["userProfile"]),
  },
  methods: {
    updateProfile() {
      this.$store.dispatch("updateProfile", {
        name: this.name !== "" ? this.name : this.userProfile.name,
        title: this.title !== "" ? this.title : this.userProfile.title,
      });

      this.name = "";
      this.title = "";

      this.showSuccess = true;

      setTimeout(() => {
        this.showSuccess = false;
      }, 2000);
    },
  },
};
</script>

<style lang="scss" scoped>
</style>

我尝试将数据部分更改为此部分,当我离开页面并返回页面时,该部分有效,但是如果我刷新页面 (F5),则字段为空,直到我离开页面并再次返回。

data() {
    return {
      name: this.$store.state.userProfile.name,
      title: this.$store.state.userProfile.title,
      showSuccess: false,
    };
  },

如果你想看的话,这是我的商店:

import Vue from "vue";
import Vuex from "vuex";
import * as fb from "../firebase";
import router from "../router/index";

Vue.use(Vuex);

// realtime firebase connection
fb.postsCollection.orderBy("createdOn", "desc").onSnapshot((snapshot) => {
  let postsArray = [];

  snapshot.forEach((doc) => {
    let post = doc.data();
    post.id = doc.id;

    postsArray.push(post);
  });

  store.commit("setPosts", postsArray);
});

const store = new Vuex.Store({
  state: {
    userProfile: {},
    posts: [],
  },
  mutations: {
    setUserProfile(state, val) {
      state.userProfile = val;
    },
    setPosts(state, val) {
      state.posts = val;
    },
  },
  actions: {
    async signup({ dispatch }, form) {
      // sign user up
      const { user } = await fb.auth.createUserWithEmailAndPassword(
        form.email,
        form.password
      );

      // create user profile object in userCollections
      await fb.usersCollection.doc(user.uid).set({
        name: form.name,
        title: form.title,
      });

      // fetch user profile and set in state
      dispatch("fetchUserProfile", user);
    },
    async login({ dispatch }, form) {
      // sign user in
      const { user } = await fb.auth.signInWithEmailAndPassword(
        form.email,
        form.password
      );

      // fetch user profile and set in state
      dispatch("fetchUserProfile", user);
    },
    async logout({ commit }) {
      await fb.auth.signOut();

      // clear userProfile and redirect to /login
      commit("setUserProfile", {});
      router.push("/login");
    },
    async fetchUserProfile({ commit }, user) {
      // fetch user profile
      const userProfile = await fb.usersCollection.doc(user.uid).get();

      // set user profile in state
      commit("setUserProfile", userProfile.data());

      // change route to dashboard
      if (router.currentRoute.path === "/login") {
        router.push("/");
      }
    },
    async createPost({ state }, post) {
      await fb.postsCollection.add({
        createdOn: new Date(),
        content: post.content,
        userId: fb.auth.currentUser.uid,
        userName: state.userProfile.name,
        comments: 0,
        likes: 0,
      });
    },
    async likePost(context, { id, likesCount }) {
      const userId = fb.auth.currentUser.uid;
      const docId = `${userId}_${id}`;

      // check if user has liked post
      const doc = await fb.likesCollection.doc(docId).get();
      if (doc.exists) {
        return;
      }

      // create post
      await fb.likesCollection.doc(docId).set({
        postId: id,
        userId: userId,
      });

      // update post likes count
      fb.postsCollection.doc(id).update({
        likes: likesCount + 1,
      });
    },
    async updateProfile({ dispatch }, user) {
      const userId = fb.auth.currentUser.uid;
      // update user object
      /*const userRef = */await fb.usersCollection.doc(userId).update({
        name: user.name,
        title: user.title,
      });

      dispatch("fetchUserProfile", { uid: userId });

      // update all posts by user
      const postDocs = await fb.postsCollection
        .where("userId", "==", userId)
        .get();
      postDocs.forEach((doc) => {
        fb.postsCollection.doc(doc.id).update({
          userName: user.name,
        });
      });

      // update all comments by user
      const commentDocs = await fb.commentsCollection
        .where("userId", "==", userId)
        .get();
      commentDocs.forEach((doc) => {
        fb.commentsCollection.doc(doc.id).update({
          userName: user.name,
        });
      });
    },
  },
  modules: {},
});

export default store;

我应该提到,这些数据正在从Firebase Fi恢复加载到状态。看起来这只是一个时间问题,数据在组件上设置data()时并没有完全加载——我添加了一些控制台日志。

Fetching user profile.. Settings.vue?e12e:29
Setting Data... index.js?4360:75
Performing setUserProfile commit.. index.js?4360:29
Setting user profile in state, last step..

再次只是对 Vue 还不够了解,不知道如何最好地改变这个顺序。

共有3个答案

孙项禹
2023-03-14

由于这只是一个时间问题:

我建议您将您的数据值绑定到您的状态的观察者。您的组件将在每次您的状态更新时简单地侦听,并相应地更新您的数据。

export default {
  data() {
    return {
      name: "",
      title: "",
      showSuccess: false,
    };
  },
  computed: {
    ...mapState(["userProfile"]),
  },
  watch: {
    userProfile: {
      handler({ name, title }) {
        this.name = name;
        this.title = title;
      },
      deep: true, // deep is to listen to objects properly
      immediate: true // immediate so the watcher triggers right away when the component is mounted
    }
  },
  methods: {
    updateProfile() {
      this.$store.dispatch("updateProfile", {
        name: this.name !== "" ? this.name : this.userProfile.name,
        title: this.title !== "" ? this.title : this.userProfile.title,
      });
      
            /*  I just wouldn't reset the values here since they'll be updated in the watcher
      this.name = "";
      this.title = ""; */

      this.showSuccess = true;

      setTimeout(() => {
        this.showSuccess = false;
      }, 2000);
    },
  },
};
况谦
2023-03-14

有两件事要注意,首先,当你想从状态 crate getter 中的变量中获取值时(作为良好的 vuex 实践):

Vuex文件:

const store = new Vuex.Store({
  state: {
    userProfile: {},
    posts: [],
  },

  getters:{
    getUserProfile: (state) => state.userProfile
  }

Settigs.vue 因此,要完成您想要的,您可以在挂载的方法中加载 data() 中的变量:

export default {
  data() {
    return {
      name: "",
      title: "",
      showSuccess: false,
    };
  },
  computed: {
    ...mapState(["getUserProfile"]),
  },

  mounted(){
   this.name = getUserProfile.name
  }

所以,如果你期望用户刷新页面而不丢失加载的数据,你不能单独使用vuex,因为当你刷新页面时,vuex系统也会重启。如果您想在刷新页面后保持加载的数据,请使用localstorage和vuex或类似的解决方案。

孟茂
2023-03-14

V-model 获取并设置您传递给它的任何值。由于要编辑状态属性,因此一旦修改

默认情况下,计算属性是一个简写,只包含getter。基本上,

computed: {
  name() {
    return this.$store.state.userProfile.name
  }
}

…可以写成:

computed: {
  name: {
    get() {
      return this.$store.state.userProfile.name
    }
  }
}

你需要的是添加一个 setter,它提交适当的突变,以便更新状态:

computed: {
  ...mapState(["userProfile"]),
  name: {
    get() {
      return this.userProfile.name
    },
    set(val) {
      this.$store.commit('setUserProfile', {
        ...this.userProfile,
        name: val
      });
    }
  },
  title: {
    get() {
      return this.userProfile.title
    },
    set(val) {
      this.$store.commit('setUserProfile', {
        ...this.userProfile,
        title: val
      });
    }
  }
}

此处记录了计算设置器。

[1]-您使用Vuex的原因是因为您不想允许任何组件直接修改您的数据。相反,您希望他们向状态提交突变,以便使用该数据的每个组件都会收到更改通知。如果您允许v-Model直接更改您的数据,您将违反不变性原则,因此您的状态将不再是唯一的真理来源。

 类似资料:
  • 本文向大家介绍vuex实现数据状态持久化,包括了vuex实现数据状态持久化的使用技巧和注意事项,需要的朋友参考一下 用过vuex的肯定会有这样一个痛点,就是刷新以后vuex里面存储的state就会被浏览器释放掉,因为我们的state都是存储在内存中的。 所以我们通过 vuex-persistedstate这个插件,来实现将数据存储到本地 用法很简单 1、 2、 以上这篇vuex实现数据状态持久化就

  • 参考 Nuxt Vuex store 的实现,Lavas 支持以模块方式组织 Vuex 的状态树。 对于开发者来说,只需要在项目根目录下 /store 文件夹中创建单独的模块文件,Lavas 会将这些单独的模块组合起来,生成最终的 Vuex.Store 实例。 下面我们以模板项目中已有的负责页面切换的 pageTransition 模块为例,介绍具体使用方法。如果您对 Vuex 尤其是模块特性还不

  • 对于每个大项目来说,使用状态树 (store) 管理状态 (state) 十分有必要。这就是为什么 Nuxt.js 内核实现了 Vuex。 在Vue School 上观看关于Nuxt.js 和 Vuex 的免费课程 使用状态树 Nuxt.js 会尝试找到应用根目录下的 store 目录,如果该目录存在,它将做以下的事情: 引用 vuex 模块 将 vuex 模块 加到 vendors 构建配置中去

  • 本文向大家介绍Ajax实现动态加载数据,包括了Ajax实现动态加载数据的使用技巧和注意事项,需要的朋友参考一下 前言: 1.这个随笔实现了一个Ajax动态加载的例子。 2.使用.net 的MVC框架实现。 3.这个例子重点在前后台交互,其它略写。 开始: 1.控制器ActionResult代码(用于显示页面) 2.前台页面主要代码 说明:这个就是要展示数据的表格,里面的字段要和你建好的模型匹配。

  • 对于每个大项目来说,使用状态树 (store) 管理状态 (state) 十分有必要。这就是为什么 Nuxt.js 内核实现了Vuex。 使用状态树 Nuxt.js 会尝试找到应用根目录下的store目录,如果该目录存在,它将做以下的事情: 引用vuex模块 将vuex模块 加到 vendors 构建配置中去 设置Vue根实例的store配置项 Nuxt.js 支持两种使用store的方式,你可以