BT6*_*643 4 javascript firebase vue.js vuex
我按照本教程尝试学习 Vue,我已经完成并且它有效,但我正在尝试做出一个我正在努力的改变。
https://savvyapps.com/blog/definitive-guide-building-web-app-vuejs-firebase
因此,有一个“设置”页面,其中包含用户个人资料(他们可以编辑自己的姓名等)。当“设置”/“个人资料”页面加载时,我希望表单加载其现有数据,以便他们可以修改它并按保存。
它当前作为占位符加载:placeholder="userProfile.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>
Run Code Online (Sandbox Code Playgroud)
我尝试将数据部分更改为此,这在我离开页面并返回时有效,但如果我刷新页面(F5),字段将为空白,直到我离开页面并再次返回。
data() {
return {
name: this.$store.state.userProfile.name,
title: this.$store.state.userProfile.title,
showSuccess: false,
};
},
Run Code Online (Sandbox Code Playgroud)
如果您需要查看的话,这是我的商店:
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;
Run Code Online (Sandbox Code Playgroud)
我应该提到的是,这些数据正在从 Firebase Firestore 加载到状态中。看起来这只是一个计时问题,在组件上设置 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..
Run Code Online (Sandbox Code Playgroud)
再说一次,我对 Vue 还不够了解,还不知道如何最好地改变这个顺序。
v-model 获取并设置您传递给它的任何值。由于您想要编辑状态属性,因此一旦您修改 的<input>值,它就会尝试更改(也称为变异)状态属性的值。这将打破不变性原则[1]。
这里的解决方案是传递一个v-model使用 getter 和 setter 的计算属性,您可以在其中告诉组件从哪里获取值以及如何更新它。
默认情况下,computed属性是简写并且仅包含 getter。基本上,
computed: {
name() {
return this.$store.state.userProfile.name
}
}
Run Code Online (Sandbox Code Playgroud)
...可以写成:
computed: {
name: {
get() {
return this.$store.state.userProfile.name
}
}
}
Run Code Online (Sandbox Code Playgroud)
您需要的是添加一个提交适当突变的设置器,以便更新状态:
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
});
}
}
}
Run Code Online (Sandbox Code Playgroud)
计算设置器记录在此处。
[1] - 你使用Vuex的原因是因为你不想让任何组件直接修改你的数据。相反,您希望它们向状态提交突变,以便使用该数据的每个组件都能收到更改通知。如果您允许v-model直接更改数据,则会违反不变性原则,因此您的状态将不再是唯一的事实来源。