Unable to receive inputs from user - vuejs3

I am using quasar cli where I initialized my quasar project and included inputs fields in a form but when I try to submit a form the fields are sent as null in the console and in the payload. Below is the code I am using :
<script>
import { defineComponent } from "vue";
import { ref } from "vue";
import emailjs from "#emailjs/browser";
export default defineComponent({
setup() {
const email = ref("");
const course = ref("");
const fname = ref("");
const phone = ref("");
const error = ref(null);
const isPwd = ref(null);
const param = {
fname: fname.value,
email: email.value,
course: course.value,
phone: phone.value,
};
const handleSubmit = async () => {
emailjs
.send("service_id", "template_id", param, "public key")
.then(
(result) => {
console.log("success", result.status, result.text, param);
},
(error) => {
console.log("FAILED...", error.text);
}
);
};
return {
handleSubmit,
email,
phone,
error,
isPwd,
fname,
course,
};
},
});
</script>
Submitting a form and checking the fields in the console

Your problem looks to be that you're sending in the param property when the form is submitted:
emailjs.send("service_id", "template_id", param, "public key")
but param, which is defined here,
const param = {
fname: fname.value,
email: email.value,
course: course.value,
phone: phone.value,
};
is not "reactive", it remains filled with the initial values of your reactive properties, null.
One Option:
A better solution is to send in data that is in fact reactive. One way to do this is via a computed property.
For example:
<template>
<form action.prevent="sendStuff">
<fieldset>
<legend>My Form</legend>
<div class="entry">
<label for="fname">First Name</label>
<input type="text" v-model="fname" id="fname" />
</div>
<div class="entry">
<label for="email">EMail</label>
<input type="email" v-model="email" id="email">
</div>
<button #click.prevent="sendStuff">
Send Data
</button>
</fieldset>
</form>
</template>
<script setup>
import { ref, computed } from 'vue'
const email = ref("");
const fname = ref("");
// const course = ref("");
// const phone = ref("");
const param1 = {
fname: fname.value,
email: email.value,
// course: course.value,
// phone: phone.value,
}
const param2 = computed(() => {
return {
fname: fname.value,
email: email.value,
// course: course.value,
// phone: phone.value,
}
});
const sendStuff = () => {
console.log('param1', param1);
console.log('param2', param2.value);
}
</script>
<style scoped>
.entry {
display: grid;
grid-template-columns: 1fr 2fr;
margin: 4px 2px;
}
</style>
Here, the first parameter property, param1, gathers data as you have been doing so, in a non-reactive way:
const param1 = {
fname: fname.value,
email: email.value,
// course: course.value,
// phone: phone.value,
}
This data will not change despite a user's entering information into your form's fields.
The second parameter example, parame2, uses a computed property to gather the information held by the form's fields:
const param2 = computed(() => {
return {
fname: fname.value,
email: email.value,
// course: course.value,
// phone: phone.value,
}
});
and here the data is reactive and changes when the user updates it.
Second Option:
Another option is to encapsulate the model into one reactive property,
const param3 = reactive({
email: '',
fname: '',
course: '',
phone: '',
});
and then send this object's values to your API. For example:
<template>
<form action.prevent="sendStuff">
<fieldset>
<legend>My Form</legend>
<div class="entry">
<label for="fname">First Name</label>
<input type="text" v-model="param3.fname" id="fname" />
</div>
<div class="entry">
<label for="email">EMail</label>
<input type="email" v-model="param3.email" id="email">
</div>
<button #click.prevent="sendStuff">
Send Data
</button>
</fieldset>
</form>
</template>
<script setup>
import { reactive } from 'vue'
const param3 = reactive({
email: '',
fname: '',
course: '',
phone: '',
});
const sendStuff = () => {
console.log(param3);
// TODO: submit form data, as param3, to the back-end
// receive asynchronous promise and handle it here
}
</script>
<style scoped>
.entry {
display: grid;
grid-template-columns: 1fr 2fr;
margin: 4px 2px;
}
</style>

As #HovercraftFullOfEels explained, param is not reactive in your code. Please consider the following option, besides the one presented in their answer:
Option 3
(a variant of Hovercraft's Option 2): use reactive, but rather than having using v-model="param.email" in template, spread it using toRefs, so you could use v-model="email":
import { toRefs, reactive } from 'vue'
// remove `fname`, `email`, `course` and `phone` refs
const param = reactive({
fname: '',
email: '',
course: '',
phone: ''
})
const { fname, email, course, phone } = toRefs(param)

I solved it by moving param inside the handlesubmit function
<script>
import { defineComponent } from "vue";
import { ref } from "vue";
import emailjs from "#emailjs/browser";
export default defineComponent({
setup() {
const email = ref("");
const course = ref("");
const fname = ref("");
const phone = ref("");
const error = ref(null);
const isPwd = ref(null);
const handleSubmit = async () => {
const param = {
fname: fname.value,
email: email.value,
course: course.value,
phone: phone.value,
};
emailjs
.send("service_id", "template_id", param, "public key")
.then(
(result) => {
console.log("success", result.status, result.text, param);
},
(error) => {
console.log("FAILED...", error.text);
}
);
};
return {
handleSubmit,
email,
phone,
error,
isPwd,
fname,
course,
};
},
});
</script>

Related

How to get the firebae document id in Vuejs 3

I'm trying to build a crud vuejs3 application (book store), and in the update operation I didn't figure out how to get the document id in order to update the book details, following are some of my code snippets where I'm currently working on:
UpdateDcoment.js
const updatingDoc = (collection, id) => {
const isPending = ref(false);
const error = ref(null);
let documentRef = db.collection(collection).doc(id);
const handleUpdateDoc = async (updates) => {
isPending.value = true;
error.value = null;
try {
const response = await documentRef.update(updates);
isPending.value = false;
console.log("update was successfully!", response);
return response;
} catch (err) {
err.value = err.message;
console.log(err.value);
error.value = err.message;
isPending.value = false;
}
};
return { error, isPending, handleUpdateDoc };
};
export default updatingDoc;
BookDetails.vue
<template>
<div>
<div v-if="document" class="book-detail-view">
<div class="book-cover">
<img :src="document.coverUrl" :alt="`${document.title} book cover`" />
</div>
<div class="book-details">
<h4 class="book-title">
{{ document.title }}
</h4>
<div class="book-description">
<p>{{ document.description }}</p>
</div>
<div class="book-author">
<p>{{ `Author: ${document.author}` }}</p>
</div>
<div v-if="currentAuthenticatedUser">
<button v-if="!isDeleting" #click="handleDelete">
Delete the book
</button>
<button v-else disabled>processing...</button>
<router-link :to="{ path: `/books/${document.id}/update` }">
Update here
</router-link>
</div>
</div>
</div>
<div v-else class="error">{{ error }}</div>
</div>
</template>
<script>
import { computed } from "#vue/runtime-core";
import getDocument from "../../controllers/getDocument";
import getUser from "../../controllers/getUser";
import deleteDocument from "../../controllers/deleteDocument";
import getStoredBook from "../../controllers/userStorage";
import { useRouter } from "vue-router";
export default {
props: ["id"],
setup(props) {
const { error, document } = getDocument("books", props.id);
const { user } = getUser();
const { removeDoc, isDeleting } = deleteDocument("books", props.id);
const { handleDeleteCover } = getStoredBook();
const router = useRouter();
const currentAuthenticatedUser = computed(() => {
return (
document.value && user.value && user.value.uid === document.value.userId
);
});
const handleDelete = async () => {
await handleDeleteCover(document.value.filePath);
await removeDoc();
router.push({ name: "home" });
};
return {
document,
error,
currentAuthenticatedUser,
handleDelete,
isDeleting,
};
},
};
</script>
UpdateBook.vue
<template>
<form #submit.prevent="handleSubmit">
<h4>Update book:</h4>
<input type="text" required placeholder="book name" v-model="title" />
<input type="text" required placeholder="author name" v-model="author" />
<textarea
required
placeholder="book description"
v-model="overview"
></textarea>
<label for="bookCover">Upload the cover book</label>
<input type="file" id="bookCover" #change="handleAddCoverBook" />
<label for="book">Upload the book</label>
<input type="file" id="book" #change="handleAddBook" />
<button v-if="!isPending">Update</button>
<button v-else disabled>Updating...</button>
<div v-if="fileError" class="error">{{ fileError }}</div>
</form>
</template>
<script>
import { ref } from "vue";
import userStorage from "#/controllers/userStorage";
import getUser from "#/controllers/getUser";
import { createdAtTime } from "#/firebase/firebaseConfig";
import { useRouter } from "vue-router";
import updatingDoc from "#/controllers/updateDocument";
export default {
setup() {
const { url1, url2, handleUploadBook, bookCoverPath, bookPath } =
userStorage();
const { user } = getUser();
const { error, isPending, handleUpdateDoc } = updatingDoc(
"books",
document.id
);
const router = useRouter();
const title = ref("");
const author = ref("");
const overview = ref("");
const bookCover = ref(null);
const book = ref(null);
const fileError = ref(null);
const handleSubmit = async () => {
if (bookCover.value) {
// Truthy value will show 'uploading...' text whenever the adding books process is processing
isPending.value = true;
await handleUploadBook(bookCover.value, book.value);
// log the result of the event listener wherever the upload was successful
console.log("book uploaded successfully", url1.value, url2.value);
const response = await handleUpdateDoc({
title: title.value,
author: author.value,
description: overview.value,
createdAt: createdAtTime(),
userId: user.value.uid,
userName: user.value.displayName,
coverUrl: url1.value,
bookUrl: url2.value,
bookCover: bookCoverPath.value,
book: bookPath.value,
});
// Truthy value will remove 'uploading...' text whenever the adding books process is finished
isPending.value = false;
if (!error.value) {
console.log("updating process successful");
router.push({ name: "BookDetail", params: { id: response.id } });
}
}
};
// Upload Cover Book
const bookCoverTypes = ["image/png", "image/jpg", "image/jpeg"];
const handleAddCoverBook = (e) => {
const newBookCover = e.target.files[0];
if (newBookCover && bookCoverTypes.includes(newBookCover.type)) {
bookCover.value = newBookCover;
fileError.value = null;
} else {
bookCover.value = null;
fileError.value = "Please add a cover book (png, jpg or jpeg)";
}
};
// Upload book
const bookTypes = ["application/pdf", "application/epub"];
const handleAddBook = (e) => {
const newBook = e.target.files[0];
if (newBook && bookTypes.includes(newBook.type)) {
book.value = newBook;
fileError.value = null;
} else {
book.value = null;
fileError.value = "Please add a book (pdf or epub)";
}
};
return {
title,
author,
overview,
handleSubmit,
handleAddCoverBook,
handleAddBook,
fileError,
isPending,
};
},
};
</script>
I'm trying to get the document id from the bookDetails.vue and then use it inside the updateBook.vue but whenever I hit the update button in the UpdateBook.vue I have the following log:
No document to update: projects/books-store-71c7f/databases/(default)/documents/books/pVIg6OytEKE4nEUE8uqd
I appreciate your hints and help guys!
SOLVED!
So, the trick was to use the params for the current URL in order to get the document id and update the document fields:
here I passing the router-link to redirect to update form:
<router-link
:to="{ name: 'UpdateBook', params: { id: document.id } }"
>
Update here
</router-link>
And here inside the setup() of the updateBook.vue component I use params to access the document id:
const router = useRouter();
// Get the current document id from the route id
const id = router.currentRoute.value.params.id;
// And here I pass the document id as parameter
const { error, isPending, handleUpdateDoc } = updatingDoc("books", id);

How to update the state in pinia with Vue 3

I'm trying to save the input values in the Pinia store, but the state is not updating. So I want onSubmit function to save the input values in a store.
My code :
Create.vue
<script setup>
import { reactive } from "vue";
import { useCounterStore } from '#/stores/counter';
const counter = useCounterStore();
const form = reactive({
first: "",
second: "",
email: ""
});
const onSubmit = (e) => {
e.preventDefault();
counter.$patch({ firstName: form.first.value });
counter.$patch({ secondName: form.second.value });
counter.$patch({ email: form.email.value });
}
</script>
<template>
<form #submit="onSubmit">
{{ counter.getFirst + 'MYFIRST' }} {{ counter.getSecond + 'MYSECOND' }} {{ counter.getEmail + 'MYEMAIL' }}
<div class="row mt-4">
<div class="col-6">
<label for="exampleFormControlInput1" class="form-label">First</label>
<input v-model="form.first" type="text" class="form-control" id="exampleFormControlInput1"
placeholder="First name">
</div> <div class="col-6">
<label for="exampleFormControlInput1" class="form-label">Second</label>
<input v-model="form.second" type="text" class="form-control" id="exampleFormControlInput1"
placeholder="Second name">
</div>
<div class="col-6 mt-2">
<label for="exampleFormControlInput1" class="form-label">Email</label>
<input v-model="form.email" type="email" class="form-control" id="exampleFormControlInput1"
placeholder="name#example.com">
</div>
<div class="col-12 mt-3">
<button #click="onSubmit" type="button" class="btn btn-dark push- right">Create</button>
<button type="button" class="btn btn-dark">All users</button>
</div>
</div>
</form>
</template>
Pinia store: counter.js
import { ref, computed, reactive } from 'vue'
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
const count = ref(0);
let firstName = ref('');
let secondName = ref('');
let email = ref('');
const getFirst = computed(() => firstName.value)
const getSecond = computed(() => secondName.value)
const getEmail = computed(() => email.value)
function increment() {
count.value++
}
return { count, getFirst, getSecond, getEmail, increment }
})
i am not sure how your store look like... but it should by something like:
`
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => {
return { count: 0 }
}
})`
in your component, change the name of the store instance, lets say counterStore.
const counterStore = useCounterStore();
and now you can access the state by name:
counterStore.counter++
while this will work, it is not the best practice...
you should use actions to manipulate the state...
export const useCounterStore = defineStore('counter', {
state: () => {
return { count: 0 }
},
actions: {
increment() {
this.count++
},
},
})
and then you can call the action like a regular method:
counterStore.increment()
I think you're in the process of learning Vue, don't give up!
Give a feedback in comment and put your post on "solved" status if this help you.
The solution :
In store file :
import { defineStore } from 'pinia';
export const useAuthStore = defineStore('auth', {
state: () => ({
loginForm: {
firstName: '',
secondName: '',
email: ''
}
})
});
In Create.vue :
<script setup>
import { reactive } from "vue";
import { useAuthStore } from '#/stores/auth';
const authstore = useAuthStore();
const form = reactive({
first: "",
second: "",
email: ""
});
...
const onSubmit = (e) => {
e.preventDefault();
authStore.loginForm.firstName = form.first;
authStore.loginForm.secondName = form.second;
authStore.loginForm.email = form.email;
}
...
<script/>

How to upload Image from Next JS Strapi API

How can I add an image from NextJS to Strapi Media library? I Try to upload the image from the NextJS frontend, the image will be uploaded to my Strapi Media library and my Cloudinary account but the image will not be associated/linked to that particular post
Here is my code
path: components/ImageUpload.js
import { useState } from "react";
import { API_URL } from "../config/index";
import styles from "#/styles/FormImage.module.css";
export default function ImageUpload({ sportNewsId, imageUploaded }) {
const [image, setImage] = useState(null);
const handleFilechange = (e) => {
console.log(e.target.files);
setImage(e.target.files[0]);
};
const handleSubmit = async (e) => {
e.preventDefault();
const formData = new FormData();
formData.append("files", image);
formData.append("ref", "sports");
formData.append("refid", sportNewsId);
formData.append("field", "image");
const res = await fetch(`${API_URL}/upload`, {
method: "POST",
body: formData,
});
if (res.ok) {
imageUploaded();
}
};
return (
<div className={styles.form}>
<h4>Upload Sport News Image</h4>
<form onSubmit={handleSubmit}>
<div className={styles.file}>
<input type="file" onChange={handleFilechange} />
<input type="submit" value="Upload" className="btn" />
</div>
</form>
</div>
);
}
path:pages/news/edit/[id].js
import Link from "next/link";
import { useState } from "react";
import Image from "next/image";
import { useRouter } from "next/router";
import moment from "moment";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import Layout from "#/components/Layout";
import { API_URL } from "#/config/index";
import styles from "#/styles/FormEdit.module.css";
import Modal from "#/components/Modal";
import ImageUpload from "#/components/ImageUpload";
export default function EditNews({ sportNews }) {
const [values, setValues] = useState({
name: sportNews.name,
detail: sportNews.detail,
date: sportNews.date,
time: sportNews.time,
});
const [previewImage, setPreviewImage] = useState(
sportNews.image ? sportNews.image.formats.thumbnail.url : null
);
const [showModal, setShowModal] = useState(false);
const router = useRouter();
const { name, detail, date, time } = values;
const handleSubmit = async (e) => {
e.preventDefault();
const emptyFieldCheck = Object.values(values).some(
(element) => element === ""
);
if (emptyFieldCheck) {
toast.error("Please fill all input field");
}
const response = await fetch(`${API_URL}/sports/${sportNews.id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(values),
});
if (!response.ok) {
toast.error("something went wrong!!!");
} else {
const sport = await response.json();
router.push(`/news/${sport.slug}`);
}
};
const imageUploaded = async (e) => {
const res = await fetch(`${API_URL}/sports/${sportNews.id}`);
const data = await res.json();
console.log("showing =>", data);
console.log(setPreviewImage);
setPreviewImage(data.image[0].formats.thumbnail.url);
setShowModal(false);
};
const handleInputchange = (e) => {
const { name, value } = e.target;
setValues({ ...values, [name]: value });
};
return (
<Layout title="Add New Sport News">
<Link href="/news">Go Back</Link>
<h2>Add Sport News</h2>
<ToastContainer />
<form onSubmit={handleSubmit} className={styles.form}>
<div className={styles.grid}>
<div>
<label htmlFor="name">Name</label>
<input
name="name"
id="name"
type="text"
value={name}
onChange={handleInputchange}
/>
</div>
<div>
<label htmlFor="date">Date</label>
<input
name="date"
id="date"
type="date"
value={moment(date).format("yyyy-MM-DD")}
onChange={handleInputchange}
/>
</div>
<div>
<label htmlFor="time">Time</label>
<input
name="time"
id="time"
type="text"
value={time}
onChange={handleInputchange}
/>
</div>
</div>
<div>
<label htmlFor="detail">Detail</label>
<textarea
name="detail"
id="detail"
type="text"
value={detail}
onChange={handleInputchange}
/>
</div>
<input className="btn" type="submit" value="Add News" />
</form>
{/* {console.log(previewImage)} */}
{previewImage ? (
<Image src={previewImage} height={100} width={180} />
) : (
<div>
<p>No Image Available</p>
</div>
)}
<div>
<button onClick={() => setShowModal(true)} className="btn-edit">
Update Image
</button>
</div>
<Modal show={showModal} onClose={() => setShowModal(false)}>
<ImageUpload sportNewsId={sportNews.id} imageUploaded={imageUploaded} />
</Modal>
</Layout>
);
}
export async function getServerSideProps({ params: { id } }) {
const res = await fetch(`${API_URL}/sports/${id}`);
const sportNews = await res.json();
return {
props: { sportNews },
};
}
this is the error message it is showing.
how do I resolve this error, any assistance will be appreciated
Thanks a lot
For a formData you have to add a header :
'Content-Type': 'multipart/form-data'
I have been struggling during hours to find this. I am uploading a file directly from an entry and not with the /upload route but it might work the same way. Using axios for the post method here is an example :
const form = new FormData();
const postData = {
name: 'test2',
};
form.append('files.image', file);
form.append('data', JSON.stringify(postData));
await axios
.post(getStrapiURL('/ingredients'), form, {
headers: {
'Content-Type': 'multipart/form-data',
},
})
.then((response) => {
// Handle success.
console.log('Well done!');
console.log('Data: ', response.data);
})
.catch((error) => {
// Handle error.
console.log('An error occurred:', error.response);
});
From my observation, the problem is on the setPreviewImage line remove the [0] array brackets from the image in order to access the Cloudinary thumbnail Url you will get from the Strapi API after each image upload.
The function below should make it work
const imageUploaded = async (e) => {
const res = await fetch(`${API_URL}/sports/${sportNews.id}`);
const data = await res.json();
console.log("showing =>", data);
console.log(setPreviewImage);
setPreviewImage(data.image.formats.thumbnail.url);
setShowModal(false);
};

Running code shows 'this.props.dispatch is not a function' after adding mapDispatchToProps

Let me tell you, this code were working fine and showing all products in shop page but after adding mapDispatchToProps.
it giving error:- TypeError: this.props.getProducts is not a function
mapStateToProps is giving products.
Trying to post data using mapDispatchToProps.
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { getProducts } from '../actions/productsAction';
import { addToCart } from '../actions/cartAction';
class Shop extends Component {
constructor(props) {
super(props);
this.state = {
pid: '',
pname: '',
pprice: '',
pimg: '',
qty: '',
total_price: '',
getValue:[]
};
}
componentDidMount() {
this.props.dispatch(getProducts());
let getValue = localStorage.getItem("userData");
this.setState({
getValue: JSON.parse(getValue),
});
}
handleSubmit = (event) => {
event.preventDefault();
const pid = this.state.pid;
const pname = this.state.pname;
const pprice = this.state.pprice;
const pimg = this.state.pimg;
const qty = this.state.qty;
const total_price = this.state.total_price;
const email = this.state.getValue.email;
const CartData = {pid: pid, pname: pname, pprice: pprice, pimg: pimg, qty:qty, total_price:total_price}
this.props.addToCart(CartData);
};
render() {
return (
...html code
<form onSubmit={ this.handleSubmit }>
<input type="hidden" onChange={this.handleChange} name="pid" value={product._id} />
<input type="hidden" onChange={this.handleChange} name="pname" value={product.pname} />
<input type="hidden" onChange={this.handleChange} name="pprice" value={product.pprice} />
<input type="hidden" onChange={this.handleChange} name="qty" value="1" />
<input type="hidden" onChange={this.handleChange} name="pimage" value={product.pimg} />
<input type="hidden" onChange={this.handleChange} name="total_price" value={product.pprice} />
<button type="submit" class="pro-btn"><i class="icon-basket"></i></button>
</form>
...html code
const mapStateToProps = (state) => ({ products: state.products });
const mapDispatchToProps = { addToCart };
export default connect(mapStateToProps, mapDispatchToProps)(Shop);
You have not defined the mapDispatchToProps properly.
It should look like below,
const mapDispatchToProps = (dispatch) => {
return {
addToCart: () => dispatch(addToCart()),
getProducts: () => dispatch(getProducts())
}
};
And you should call the function directly using props
componentDidMount() {
this.props.getProducts();
let getValue = localStorage.getItem("userData");
this.setState({
getValue: JSON.parse(getValue),
});
}
You have two actions that you want to use in your component, so you'll want to include them both in your mapDispatchToProps object. The function notation described by #AmilaSenadheera will work, but the object shorthand is easier.
const mapDispatchToProps = {
addToCart,
getProducts
};
Then you should be able to call this.props.getProducts().

Updating user profile information with redux in firebase

I am trying to use Redux in my React application to update the user profile within my Firebase database from my react component.
This is my component:
import { connect } from "react-redux";
import { Redirect } from "react-router-dom";
import { firestoreConnect } from "react-redux-firebase";
import { compose } from "redux";
import { editProfile } from "../../store/actions/editProfileActions";
class UserProfile extends Component {
state = {
firstName:"",
initials:"",
lastName:""
};
onChange = e => {
this.setState({
[e.target.id]: e.target.value
});
};
onSubmit = e => {
e.preventDefault();
console.log(this.state);
this.props.editProfile(this.state);
}
render() {
const { auth, profile } = this.props;
console.log(profile);
if (auth.isEmpty) return <Redirect to="/home" />;
return (
<div className="container">
<form onSubmit={this.onSubmit} className="white">
<h5 className="grey-text text-darken-3">Edit Profile</h5>
<div className="input-field">
<label htmlFor="title">First Name: {profile.firstName}</label>
<input type="text" id="firstName" onChange={this.onChange} />
</div>
<div className="input-field">
<label htmlFor="title">Initials: {profile.initials}</label>
<input type="text" id="initials" onChange={this.onChange} />
</div>
<div className="input-field">
<label htmlFor="title">Last Name: {profile.lastName}</label>
<input type="text" id="lastName" onChange={this.onChange} />
</div>
<div className="input-field">
<button className="btn black z-depth-0">Submit</button>
{ }
</div>
</form>
</div>
)
}
};
const mapStateToProps = state => {
return {
auth: state.firebase.auth,
profile: state.firebase.profile,
};
};
const mapDispatchToProps = dispatch => {
return {
editProfile: edit => dispatch(editProfile(edit))}
}
export default compose(
connect(mapStateToProps, mapDispatchToProps),
firestoreConnect([
{ collection: "profile"}
])
)(UserProfile);
The component correctly displays the current user information.
This is the action I have set up:
return async (dispatch, getState, { getFirestore, getFirebase }) => {
const firebase = getFirebase();
const user = await firebase
.auth()
.currentUser
.updateProfile({
firstName: profile.firstName
});
dispatch({ type: "EDITPROFILE_SUCCESS", user })
console.log("user = " + profile.firstName);
};
}
When I log the entered profile.firstName I get the entered data.
And my reducer:
const editProfileReducer = (state, action) => {
switch (action.type) {
case "EDITPROFILE_ERROR":
return {
...state,
editError: action.error
};
case "EDITPROFILE_SUCCESS":
return {
...state
};
default:
return state;
}
}
export default editProfileReducer;
Any idea what I am missing here?
In your reducer change the like below
case "EDITPROFILE_SUCCESS":
return {
...state,
user:action.user
};
Above is if you want to update the whole user object
If you want to change only name then
Let’s assume that profileName is in user object then
case "EDITPROFILE_SUCCESS":
return {
...state,
user:Object.assign({}, state.user, profileName:action.user.profileName)
};

Resources