Why is my state's value is always undefined? - reactjs

I've read all the question asked that similar to my problem , but it still cant's solve my issues . I'm fetching datas from an api and assign it's values into my state , the program compiled successfully but this message appears in the browser "TypeError: weatherData.main is undefined"
Here's my code
import './App.css';
import React,{useEffect,useState} from 'react';
function App() {
const [weatherData,setWeatherData] = useState({});
const [position,setPosistion] = useState({});
useEffect(()=>{
navigator.geolocation.getCurrentPosition( pos => {
setPosistion(()=>{
return {
latitude : pos.coords.latitude,
longitude : pos.coords.longitude
}
})
});
},[])
useEffect(()=>{
fetch(`https://api.openweathermap.org/data/2.5/weather?lat=${position.latitude}&lon=${position.longitude}&units=metric&appid=a*****5`)
.then( res => res.json() )
.then( resJson => {
setWeatherData(()=>resJson)
})
},[position]);
return (
<div className="App">
<Weather weatherData={weatherData} />
</div>
);
}
const Weather = ({weatherData}) => {
return(
<React.Fragment>
<div className="location-time">
<span id="location">{weatherData.name}</span>
</div>
<div className="weather">
<span className="temp">{`${weatherData.main.temp} C`}</span>
<div className="icon"></div>
<div className="description">{weatherData.weather[0].main}</div>
<div className="low-max">{`max : ${weatherData.main.temp_max} min : ${weatherData.main.temp_min}`}</div>
<div className="feels-like">{`feels like : ${weatherData.main.feels_like}`}</div>
<button >REFRESH</button>
</div>
</React.Fragment>
)
}
export default App;
the state contains
{"coord":{"lon":106.8451,"lat":-6.2146},"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"}],"base":"stations","main":{"temp":302.76,"feels_like":307.06,"temp_min":300.15,"temp_max":305.93,"pressure":1007,"humidity":74},"visibility":6000,"wind":{"speed":2.57,"deg":340},"clouds":{"all":40},"dt":1613038370,"sys":{"type":1,"id":9383,"country":"ID","sunrise":1612997835,"sunset":1613042198},"timezone":25200,"id":1642911,"name":"Jakarta","cod":200}

Before the data is fetched, weather is initialised to be a empty object and hence weather.main is undefined.
You should consider rendering a fallback page till weather data is fetched
const Weather = ({weatherData}) => {
if(Object.keys(weatherData).length === 0) {
return <div>{/* Somee info here or maybe a loader*/}</div>
}
return(
<React.Fragment>
<div className="location-time">
<span id="location">{weatherData.name}</span>
</div>
<div className="weather">
<span className="temp">{`${weatherData.main.temp} C`}</span>
<div className="icon"></div>
<div className="description">{weatherData.weather[0].main}</div>
<div className="low-max">{`max : ${weatherData.main.temp_max} min : ${weatherData.main.temp_min}`}</div>
<div className="feels-like">{`feels like : ${weatherData.main.feels_like}`}</div>
<button >REFRESH</button>
</div>
</React.Fragment>
)
}

Related

React Hooks: Can't perform a React state update on a component that hasn't mounted yet

Edit 1
I have updated my code (changed from useState to useEffect) but seems like the same problem. Only if I remove the return code, it runs perfectly. Seems like it happens when I have lots of data to show in view
Edit 2
I updated my useEffect() to below but still the same problem.
useEffect(() => {
let mounted = true;
if (mounted) {
FetchOrderDetails();
}
return () => (mounted = false);
}, []);
Edit Ends
I get this warning sometimes and it crashes Warning: Can't perform a React state update on a component that hasn't mounted yet. This indicates that you have a side-effect in your render function that asynchronously later calls tries to update the component. Move this work to useEffect instead.
Surprisingly, sometimes the code runs perfectly which most of the time it doesn't. What is wrong?
My code
import React, { useState } from "react";
import { useParams } from "react-router-dom";
import { useCookies } from "react-cookie";
import * as Constants from "../Constants";
import HeaderTemplate from "../Templates/HeaderTemplate";
const OrderDetails = () => {
const { transactionRefNo, transactionId } = useParams();
const [cookies] = useCookies(["user"]);
const [orderDetails, setOrderDetails] = useState([]);
const FetchOrderDetails = async () => {
let options = {
employeeid: parseInt(cookies.employeeId),
transactionid: parseInt(transactionId),
};
await fetch(Constants.API_ENDPOINT + "/test/orderdetails", {
method: "POST",
body: JSON.stringify(options),
})
.then((response) => response.json())
.then((data) => setOrderDetails(data.order));
};
useEffect(() => {
console.log(transactionRefNo, transactionId);
FetchOrderDetails();
}, []);
return (
<div>
<HeaderTemplate />
<React.Fragment>
{/* Order Details Starts*/}
<div className="panel panel-default mt-4">
<div className="panel-heading">
<h6 className="panel-title">Order Details</h6>
</div>
<div className="panel-body">
<b>
<small>
{"Order #" +
orderDetails["transaction_reference_no"]}
</small>
</b>
<div className="row">
<div className="col-md-6">
<small>Port: {orderDetails["port"]}</small>
</div>
</div>
<div className="row">
<div className="col-md-6">
<small>
Type:{" "}
{orderDetails["transaction_type"] ===
"selling_stages"
? "Selling"
: "Buying"}
</small>
</div>
</div>
</div>
</div>
{/* Order Details Ends*/}
</React.Fragment>
</div>
);
};
export default OrderDetails;
It turns out, useEffect tries to update the state both when it mounts and unmounts. Hence the error occurs. As suggested by #super, I used swr to circumvent the issue in my case
import React from "react";
import { useParams } from "react-router-dom";
import { useCookies } from "react-cookie";
import * as Constants from "../Constants";
import HeaderTemplate from "../Templates/HeaderTemplate";
const fetcher = async (cookies, transactionId) => {
let options = {
employeeid: parseInt(cookies.employeeId),
transactionid: parseInt(transactionId),
};
const res = await fetch(Constants.API_ENDPOINT + "/test/orderdetails", {
method: "POST",
body: JSON.stringify(options),
});
const json = await res.json();
return json;
};
const OrderDetails = () => {
const { transactionRefNo, transactionId } = useParams();
const [cookies] = useCookies(["user"]);
const { data, error } = useSwr([cookies, transactionId], fetcher);
if (!data) return <div>Loading...</div>;
if (error) return <div>Error</div>;
return (
<div>
<HeaderTemplate />
<React.Fragment>
{/* Order Details Starts*/}
<div className="panel panel-default mt-4">
<div className="panel-heading">
<h6 className="panel-title">Order Details</h6>
</div>
<div className="panel-body">
<b>
<small>
{"Order #" +
data.order.transaction_reference_no}
</small>
</b>
<div className="row">
<div className="col-md-6">
<small>Port: {data.order.port}</small>
</div>
</div>
<div className="row">
<div className="col-md-6">
<small>
Type:{" "}
{data.order.transaction_type ===
"selling_stages"
? "Selling"
: "Buying"}
</small>
</div>
</div>
</div>
</div>
{/* Order Details Ends*/}
</React.Fragment>
</div>
);
};
export default OrderDetails;

copying to clipboard react

I'm trying to copy a text to clipboard using a button, the code working fine but the problem is copying another post text not the targeted one! I have multi posts using map. and each post has a text and a button, the issue now is when i'm hitting the button it copies the first post text!
The code for Post.jsx
export default function Post({ post }) {
var cpnBtn = document.getElementById("cpnBtn");
var cpnCode = document.getElementById("cpnCode");
const CopyCode = () => {
navigator.clipboard.writeText(cpnCode.innerHTML);
cpnBtn.innerHTML = "COPIED";
setTimeout(function(){
cpnBtn.innerHTML = "COPY CODE";
}, 3000);
}
return (
<div className="coupon">
<div className="coupon-container">
<div className="coupon-card">
<div className="postInfo">
{post.photo && <img className="postImg" src={post.photo} alt="" />}
<div className="postTitle">
<span >{post.shop}</span>
</div>
<div className="postTitle">
<span >{post.title}</span>
</div>
<div className="coupon-row">
<span id="cpnCode">{post.coupon}</span>
<button id="cpnBtn" onClick={CopyCode}>COPY CODE</button>
</div>
</div>
</div>
</div>
</div>
);
}
The code for Posts.jsx
export default function Posts({ posts }) {
return (
<div className="posts">
{posts.map((p) => (
<Post post={p} />
))}
</div>
);
}
The reason why it's copying always the first coupon is that you're rendering multiple posts and all have a coupon with id="cpnCode" so it will always use the top one. Besides that, I've explained below the proper way to implement such functionality in react.
The easiest way to solve this would be to use the useState of react to hold the text of the button in it. When using react we try to avoid mutating DOM elements manually instead we rely on to react to perform these updates.
Also, there's no need to take the coupon value from the coupon HTML element if you already have access to the post.
writeText is a Promise that's why I added the then block and the catch so you can see the error in your console in case something goes wrong.
import { useState } from "react";
export default function Post({ post }) {
const [bttnText, setBttnText] = useState("COPY CODE");
const copyCode = () => {
navigator.clipboard
.writeText(post.coupon)
.then(() => {
setBttnText("COPIED");
setTimeout(function () {
setBttnText("COPY CODE");
}, 3000);
})
.catch((err) => {
console.log(err.message);
});
};
return (
<div className="coupon">
<div className="coupon-container">
<div className="coupon-card">
<div className="postInfo">
{post.photo && <img className="postImg" src={post.photo} alt="" />}
<div className="postTitle">
<span>{post.shop}</span>
</div>
<div className="postTitle">
<span>{post.title}</span>
</div>
<div className="coupon-row">
<span>{post.coupon}</span>
<button onClick={copyCode}>{bttnText}</button>
</div>
</div>
</div>
</div>
</div>
);
}
Alterantively in case you really need to access the htmlElements it can be done with useRef e.g
import { useState, useRef } from "react";
export default function Post({ post }) {
const [bttnText, setBttnText] = useState("COPY CODE");
const couponRef = useRef();
const copyCode = () => {
// just a safety mechanism to make sure that
// the references found the DOM elmenets button and coupon
// before trying to use them
if (!couponRef.current) return;
navigator.clipboard
// again doesn't make sense to use here
// couponRef.current.innerHTML
// since you got access to post.coupon
.writeText(couponRef.current.innerHTML)
.then(() => {
setBttnText("COPIED");
setTimeout(function () {
setBttnText("COPY CODE");
}, 3000);
})
.catch((err) => {
console.log(err.message);
});
};
return (
<div className="coupon">
<div className="coupon-container">
<div className="coupon-card">
<div className="postInfo">
{post.photo && <img className="postImg" src={post.photo} alt="" />}
<div className="postTitle">
<span>{post.shop}</span>
</div>
<div className="postTitle">
<span>{post.title}</span>
</div>
<div className="coupon-row">
<span ref={couponRef}>{post.coupon}</span>
<button onClick={copyCode}>{bttnText}</button>
</div>
</div>
</div>
</div>
</div>
);
}

React Owl Carousel 2.3.3 - I loose dynamic data after refreshing page. Working fine on local data

I am using json-server and fetching data using fetch. First time I get data properly in an Owl Carousel and the slider works fine but after when I refresh the page all my dynamic data wipe out. Still my carousel slides but with no data. Also I have attached a jquery script https://code.jquery.com/jquery-3.2.1.slim.min.js in index.html.
I am loosing my Owl Carousel Dynamic Data which I am using through map method in the Owl Carousel Component. Below is the code where I am using my slider. Please help me to find where I am doing wrong. Thank You.
---------------
<<<<<- Below code is MainSlider.js ->>>>>
import React, { useReducer, useEffect } from "react";
import OwlCarousel from "react-owl-carousel";
import "owl.carousel/dist/assets/owl.carousel.css";
import { mainSliderReducer } from "../reducers/mainSliderReducer";
const API = "http://localhost:8000/mainSlider";
const initialState = {};
const MainSlider = () => {
const [state, dispatch] = useReducer(mainSliderReducer, initialState);
const { data } = state;
useEffect(() => {
getData();
}, []);
const getData = () => {
fetch(API)
.then((res) => {
if (res.ok) {
return res.json();
} else {
console.log("DATA NOT FOUND. SOME ERROR");
throw new Error("ERROR FETCHING DATA");
}
})
.then((data) => dispatch({ type: "GET_MAINSLIDER_DATA", payload: data }))
.catch((err) => console.log(err));
};
console.log(data);
return (
<>
<OwlCarousel className="owl-theme" loop margin={10} nav>
{data ? (
data.map((item) => {
const { id, heading, description, img, smallHeading } = item;
return (
<section key={id} className="dvMainSlider">
<div className="item bg bgcolor1 pb-md-5 pt-md-4 py-xl-0 h-100vh h-sm-auto h-xl-100vh">
<div className="container">
<div className="row slideInfo h-xl-100vh align-items-xl-center">
<div className="col-md-6 text-center">
<img
src={img}
className="img-fluid d-inline-block"
alt=""
/>
</div>
<div className="col-md-6 pt-lg-5 pt-xl-0 description">
<h1 className="text-white">{heading}</h1>
<h4 className="text-white">{smallHeading}</h4>
<p className="text-white">{description}</p>
<a href="--" className="btn btnPrimary mb-3 mt-sm-3">
Shop More
</a>
</div>
</div>
</div>
</div>
</section>
);
})
) : (
<h1>"SLIDE NOT FOUND"</h1>
)}
</OwlCarousel>
</>
);
};
export default MainSlider;
<<<<<- Below code is mainSliderReducer.js ->>>>>
export const mainSliderReducer = (state, action) => {
console.log(state, action);
switch (action.type) {
case "GET_MAINSLIDER_DATA":
return { ...state, data: action.payload };
default:
return state;
}
};
Hey I found my own question's answer and i found the way which i am sharing to you all. Just check if data is available then only you load the Owl Carousel Component. Check the code below for better understanding.
{data && (
<OwlCarousel {...options}>
{data.map((item) => {
const { id, heading, description, img, smallHeading } = item;
return (
<section key={id} className="dvMainSlider">
<div className="item bg bgcolor1 pb-md-5 pt-md-4 py-xl-0 h-100vh h-sm-auto h-xl-100vh">
<div className="container">
<div className="row slideInfo h-xl-100vh align-items-xl-center">
<div className="col-md-6 text-center">
<img
src={img}
className="img-fluid d-inline-block"
alt=""
/>
</div>
<div className="col-md-6 pt-lg-5 pt-xl-0 description">
<h1 className="text-white">{heading}</h1>
<h4 className="text-white">{smallHeading}</h4>
<p className="text-white">{description}</p>
<a href="--" className="btn btnPrimary mb-3 mt-sm-3">
Shop More
</a>
</div>
</div>
</div>
</div>
</section>
);
})}
</OwlCarousel>
)}

Content not displayed despite present data - React

Could you tell me why my offer content is always empty ?
The "toto" is not displayed and my data are displayed because of the line "console.log(offers").
const ListProduct = (offers : any) => {
console.log(offers);
const offersDisplay = offers ? (
<div>
{ () => {
console.log("test");
offers.map((shop :any) => {
shop.offers.map((offer:any) => {
return(
<div className="card border-secondary mb-3 listMaxWidth">
<div className="card-header">{shop.name}</div>
<div className="card-body">
<img src={offer.picture} className="imgOffer"/>
<h4 className="card-title">{offer.name}</h4>
<p className="card-text">{shop.description}</p>
</div>
</div>
);
});
})
}
}
</div>
):'toto';
return(
<div>
{offersDisplay }
</div>
)
}
export default ListProduct;
I tried so many different way to write it, unfortunately can't find the right way ...
Could you help me please ?
Thanks in advance
You don't need to pass a callback function in your code
const offersDisplay = offers ? (
<div>
//this callback
{ () => {
And also you don't return from your first map.
And the last thing is that you need to include the code in your return that way it gets executed every time the offers data is changed.
You need to change your code like this
const ListProduct = (offers : any) => {
return(
<div>
{
offers && offers.length && offers.map((shop :any) => {
return shop.offers.map((offer:any) => {
return(
<div className="card border-secondary mb-3 listMaxWidth">
<div className="card-header">{shop.name}</div>
<div className="card-body">
<img src={offer.picture} className="imgOffer"/>
<h4 className="card-title">{offer.name}</h4>
<p className="card-text">{shop.description}</p>
</div>
</div>
);
});
})
}
</div>
)
}
export default ListProduct;

Undefined when Filtering an Array in React JS

I am trying to filter an array in React for only certain items (in my case I want all items that have type: "Plant"). I can get the data from an API successfully but filtering its produces this error: Unhandled Rejection (TypeError): undefined is not an object (evaluating 'data.Array.object')
Here is what the data looks like if I console log it:
data
Here is my full code:
import React from "react";
import { API, graphqlOperation } from 'aws-amplify';
import { listTrackerItems } from '../graphql/queries';
class TrackerPlantsPage extends React.Component {
state = {
plant:'',
plants: [],
active: []
};
async componentDidMount() {
const result = await API.graphql(graphqlOperation(listTrackerItems))
let data = result.data.listTrackerItems.items
console.log(data)
let activePlants = data.Array.filter(t=>t.type === 'Plant');
this.setState({active: activePlants, plants: data });
}
render() {
const { plants, active } = this.state
console.log(plants)
return (
<>
<div class="container">
{/* Cards */}
<div id="toggle-harvested" class="">
<div class="uk-child-width-1-3 uk-grid-small uk-grid-match uk-grid">
{plants.map(item => (
<div key={item.id} class="uk-margin-top uk-margin-bottom">
<div class="uk-card uk-card-secondary uk-card-body">
<div class="uk-card-badge uk-label">Harvested on {item.harvestDate}</div>
<div class="uk-child-width-expand#s uk-text-center" uk-grid>
<div>
<div>
<h3 class="uk-card-title uk-margin-remove-bottom">{item.name}</h3>
</div>
</div>
</div>
<ul class="uk-list uk-list-striped">
<li>Planted: {item.todaysDate}</li>
<li>Assigned: {item.assignedUser}</li>
<li>{item.description}</li>
</ul>
</div>
</div>
))}
</div>
</div>
</div>
</div>
</>
)
}
}
export default TrackerPlantsPage;
Regards
do data.filter(t => t.type === 'Plant') instead.

Resources