I want to send the login user object to the profile page to edit and upload an image but It ends with the error "ProfileImage.jsx:25 Uncaught TypeError: Cannot read properties of undefined (reading 'photoUrl')"
Here is my Parent Code :
import React from 'react';
import { useState } from 'react';
import {getCurrentUser, logout} from '../../services/authService'
import {useNavigate} from "react-router-dom";
import UpdateForm from '../../components/UpdateForm';
import ProfileImage from '../../components/ProfileImage';
import './Profile.css'
import { useEffect } from 'react';
const ProfilePage = () => {
const navigate = useNavigate();
const [user,setUser] = useState();
useEffect(()=>{
const getUser = async () => {
const {data} = await getCurrentUser();
setUser(data);
}
getUser()
},[])
const handelSignOut =()=>{
logout();
setUser('');
navigate('/sign')
}
return (
<div className='prof-con'>
<div className='prof-flex-wraper'>
<div className='prof-second-row'>
<div className='prof-text'>
<ProfileImage user={user}/>
</div>
<div className='prof-form'>
<UpdateForm user={user}/>
</div>
</div>
</div>
</div>
);
}
export default ProfilePage;
and here is the profile Child component
import React from 'react';
import { useState } from 'react';
import {updatePhoto} from '../services/authService'
import DefaultUserPic from "../images/team-male.jpg";
function ProfileImage({user}) {
const [previewSrc,setPreviewSrc] = useState(null)
const [photoSrc,setPhotoSrc] = useState(null)
const handelPreview = (e)=>{
setPreviewSrc(URL.createObjectURL(e.target.files[0]))
setPhotoSrc(e.target.files[0]);
}
const handelUpload = ()=>{
const formData = new FormData();
console.log(photoSrc)
formData.append("file", photoSrc);
updatePhoto(formData);
}
//console.log(user.photoUrl)
console.log(user)
// if(previewSrc){
// var imagestr=previewSrc;
// console.log(imagestr)
// // imagestr = imagestr.replace("public/", "");
// // var profilePic="http://localhost:3001/"+imagestr;
// }else{
// var profilePic='DefaultUserPic';
// }
return (
<div className='profWraper'>
<input type="file" name="fileToUpload" id="fileToUpload" onChange={handelPreview}/>
<img className='profPhoto' src={previewSrc} alt="No-Image" />
{photoSrc && <button className='uploadBtn' onClick={handelUpload}>Upload</button>}
</div>
);
}
export default ProfileImage;
if I log the user itself I get it in the console but if I try to get any property get an error undefined.
Changing
<ProfileImage user={user}/>
to
{user && <ProfileImage user={user}/>}
might help
You are asynchronously assigning user within the useEffect of ProfileImage. That means user will be undefined until that asynchronously logic resolves. You either have to check to see if user is defined before accessing its properties, or you need to assign user some kind of default properties in your useState.
The error message suggests that user is undefined. Considering that the parent performs an async operation to get the user, I'd say the problem is that the child tries to access the user before the async operation is resolved.
Solution, add a guard against undefined user in the child:
if (user === undefined) return
Related
Hi everyone I am trying to build a chat app but I have a problem
this is my getCollection.js file that contains the request of getting the messages from firebase
import { ref } from "vue"
import {projectfirestore} from "./../../cons"
import { collection ,getDocs,query, orderBy} from "firebase/firestore";
const Doc = ref([])
const error = ref(null)
const getCollection = async (collectionName)=>{
const collectionq = query(collection(projectfirestore,collectionName), orderBy("createdAt"))
await (await getDocs(collectionq)).forEach(doc=>{
doc.data().createdAt && Doc.value.push({...doc.data(),id:doc.id})
})
if (!Doc.value) {
error.value = "could not fetch the data"
Doc.value = null
}
console.log("docs.value",Doc.value)
console.log("error].value",error.value)
return { error, Doc }
}
export default getCollection
and as you see there is two console.log() at the end of the function
so it fetches the data correctly
now this is the ChatWindow.vue
<template>
<div class="chat-window">
<div v-if="error">{{error}}</div>
<div v-if="Doc" class="messages">
<div v-for="doc in Doc" :key="doc.id" class="single">
<span class="created-at">{{doc.createdAt}}</span>
<span class="name">{{doc.name}}</span>
<span class="message">{{doc.message}}</span>
</div>
</div>
</div>
</template>
<script>
import getCollection from '../composables/getCollection.js'
export default {
setup(){
const {error , Doc} = getCollection('message')
console.log("docskk.value",Doc)
console.log("errorkk.value",error)
return {Doc, error}
}
}
</script>
the same here I have two console.log() and this is there values
I would mention that the 2 console.log() in ChatWindow.vue printed before those on the getCollection.js
the expected result is that it must print the message information of the user above the message text field
and I am sure that the component is placed in the View
as it is in this Chatroom.vue
<template>
<div class="container">
<Navbar />
<ChatWindow />
<NewChatRoom />
</div>
</template>
<script>
import Navbar from '#/components/Navbar.vue';
import getUser from '#/composables/getUser';
import { watch } from '#vue/runtime-core';
import { useRouter } from 'vue-router';
import NewChatRoom from '#/components/NewChatRoom.vue';
import ChatWindow from '#/components/ChatWindow.vue';
export default {
components: { Navbar, NewChatRoom, ChatWindow },
setup(){
const {user } = getUser()
const router = useRouter()
watch(user,()=>{
if(!user.value){
router.push({name:"Welcome"})
}
})
}
}
</script>
and when I try to put await before the function call
async setup(){
const {error , Doc} = await getCollection('message')
return {Doc, error}
}
it doesn't show the ChatWindow.vue component on Chatroom.vue view
You should use await when reading asynchronous data.
Use
<script>
import getCollection from '../composables/getCollection.js'
export default {
async setup(){
const {error , Doc} = await getCollection('message')
console.log("docskk.value",Doc)
console.log("errorkk.value",error)
return {Doc, error}
}
}
</script>
then wrap it using defineAsyncComponent
const ChatWindow = defineAsyncComponent(() =>
import('#/components/ChatWindow.vue')
)
read https://vuejs.org/guide/components/async.html#basic-usage
import logo from './logo.svg';
i need to list items from my appsync api in my react app ...i cant display as it says the error its undefined ...which i mentioned bellow the code..i know my code is wrong can somebody guide me
import React, { useState } from "react";
import { API, graphqlOperation } from 'aws-amplify';
import { listTestModels } from "./graphql/queries/list";
import './App.css';
function App() {
const [list, setBook] = useState(null);
const getBook = async () => {
// make a call to appsync api
const list = await API.graphql(graphqlOperation(listTestModels));
setBook(list.data.listTestModels.items);
}
const viewBook = () => {
if (list) {
**it shows error after this **
return (<article>
<h3>{list.data.listTestModels.items}</h3>
<p>{list.Location}</p>
<p>{list.Email}</p>
</article>)
}
}
return (
<div>
<section className="book-section">
<button onClick={() => getBook()}>Get book details</button>
<hr />
{viewBook()}
</section>
</div>
);
}
export default App;```
**it shows error App.js:24 Uncaught TypeError: Cannot read properties of undefined (reading 'listTestModels')**
list.data is undefined. Change the condition to list && list.data
const viewBook = () => {
if (list && list.data) {...}
}
But if the data key doesn't exist in the list object . It will never render the viewBook.
I am trying to create a simple web application which lists products from fakestore api using REACT REDUX. But react is throwing the error "TypeError: Cannot read properties of undefined (reading 'map')".
productListing.jsx
import React, { useEffect } from 'react';
import axios from 'axios';
import { useDispatch, useSelector } from 'react-redux';
import { setProducts } from '../redux/actions/productActions';
import ProductComponent from './ProductComponent';
const ProductListing = () => {
// const products = useSelector((state) => state.allProducts.products);
const dispatch = useDispatch()
const fetchProducts = async () => {
const response = await axios
.get("https://fakestoreapi.com/products")
.catch((err) => {
console.log("Err: ", err);
});
dispatch(setProducts(response.data));
console.log(response.data)
};
useEffect(() => {
fetchProducts()
},[])
// console.log("Products :" , products)
return (
<div className="ui grid container">
<ProductComponent />
</div>
);
};
export default ProductListing;
The above component is responsible for api call from fakestoreapi and updating the redux store.
In the following component named "productComponent.jsx" i tried to list the products from the redux store using map method which is as follows :
import React from 'react'
import { useSelector } from 'react-redux'
const ProductComponent = () => {
const pdts = useSelector((state) => state.allProducts.products);
// console.log(typeof(pdts))
console.log("Products",pdts)
const renderList = pdts.map((pdt) => {
// const { id, title, image, price, category } = pdt;
return(
<div className="four column wide" key={pdt.id}>
<div className="ui link cards">
<div className="card">
<div className="image">
<img src={pdt.image} alt={pdt.title} />
</div>
<div className="content">
<div className="header">{pdt.title}</div>
<div className="meta price">$ {pdt.price}</div>
<div className="meta">{pdt.category}</div>
</div>
</div>
</div>
</div>
)
})
return(
<>{renderList}</>
// <>gbdf</>
)
}
export default ProductComponent
But React is throwing the folowing error :
Error Image
when i consoled the products object it shows undefined. But after I commented renderlist and again consoled the products object it consoled two time with the first one being undefined and second one printing the correct object with values. At this point of time I uncommented the render list, now the react is listing the products but when i again reload the page it consoles undefined value for two times.
Pdts is undefined in the first render. Hence cant be mapped.
Try this
pdts?.map()
It's known as Optional Chaining.
Weather.JS File
import { useEffect, useState } from "react"
import axios from 'axios'
import WeatherDisplay from './WeatherDisplay'
const Weather = ({capital, params}) => {
const [weather,setWeather] = useState([])
useEffect(async () => {
const result = await axios.get('http://api.weatherstack.com/current', {params})
console.log(result.data)
setWeather(result.data)
},
[params])
return(
<div>
<h2>Weather in {capital}</h2>
<WeatherDisplay current={weather.current}/>
</div>
)
}
export default Weather
WeatherDisplay.js File
const WeatherDisplay = ({weather}) => {
console.log(weather.current.temperature)
return (
<h1>{weather.current.temperature}</h1>
)
}
export default WeatherDisplay
Having issues display the data when i use {weather.current.temperature}, it keeps giving me an error pointed at temperuture saying it isnt defined but its apart of the data
You are passing weather.current as props. While the child component is expecting weather as prop. So, what you end up doing is weather.current.current.temperature which is undefined because it doesn't exist. Just pass weather to the child prop.
Make this change when calling your child component.
<WeatherDisplay weather={weather}/>
I'm trying to do some small exercises in react, but here I got some error:
Cannot read property 'name' of undefined
Could anyone help me, please?
import React, {useState, useEffect} from 'react';
import FriendProfile from './FriendProfile';
import Button from './Button';
const Friend = () => {
const [friend, setFriend] = useState({})
async function getFriend() {
try{
const response = await fetch('https://www.randomuser.me/api?results=1')
const data = await response.json()
const [item] = data.results;
setFriend(item)
}catch(err){
console.log(err)
}
}
useEffect(() => {
getFriend()
}, [])
return (
<div>
<Button getFriend={getFriend} />
<FriendProfile />
</div>
);
};
export default Friend;
and FriendProfile component is:
import React from 'react';
const FriendProfile = ({friend}) => {
return (
<ul>
<li>{friend.name.first}</li>
</ul>
);
};
export default FriendProfile;
You forgot to pass to <FriendProfile /> component the friend object. In the child component it tries to destructure like ({friend}) but there is no value there. That's why you are getting that error message.
Try to pass as the following:
<FriendProfile friend={friend} />
Then in the <FriendProfile> component you need to do the additional conditional rendering:
<ul>
{
friend.name &&
<li>{friend.name.first}</li>
}
</ul>
Technically we are checking if friend.name has value or not. Once the API call returned and updated the state, it will render the <li> element with the first name of the friend object.
I hope this helps!