I am getting state undefined error when reloading page - javascript

Everything is fine the first time but get error and undefined state the time I refresh the page
and also if I comment the h1 and p tags and uncomment then the error resolves and hits again I refresh
Here is my code
import { useState, useEffect } from "react";
function App() {
var [state, setState] = useState({});
useEffect(() => {
fetch(
"https://api.openweathermap.org/data/2.5/find?q=kolkata&units=metric&appid=907c99e1a96b5d38487d8d9c19b413fc"
)
.then((doc) => {
return doc.json();
})
.then((doc) => {
setState(doc);
});
}, []);
return (
<div className="App">
<div className="welcome">
<h1>
{state.list[0].main.temp}
<sup> o</sup>C
</h1>
<p>Feels Like {state.list[0].main.feels_like}</p>
<img src="https://openweathermap.org/img/w/50d.png" alt="haze" />
</div>
</div>
);
}
export default App;

Your state is an empty object Initially ,you have to put a check ,like I did below.
import { useState, useEffect } from "react";
function App() {
var [state, setState] = useState({});
useEffect(() => {
fetch(
"https://api.openweathermap.org/data/2.5/find?q=kolkata&units=metric&appid=907c99e1a96b5d38487d8d9c19b413fc"
)
.then((doc) => {
return doc.json();
})
.then((doc) => {
setState(doc);
});
}, []);
return (
<div className="App">
<div className="welcome">
{Object.keys(state).length>0?<><h1>
{state.list[0].main.temp}
<sup> o</sup>C
</h1>
<p>Feels Like {state.list[0].main.feels_like}</p></>:""}
<img src="https://openweathermap.org/img/w/50d.png" alt="haze" />
</div>
</div>
);
}
export default App;
or If you want to avoid Object.keys make default state null
import { useState, useEffect } from "react";
function App() {
var [state, setState] = useState(null);
useEffect(() => {
fetch(
"https://api.openweathermap.org/data/2.5/find?q=kolkata&units=metric&appid=907c99e1a96b5d38487d8d9c19b413fc"
)
.then((doc) => {
return doc.json();
})
.then((doc) => {
setState(doc);
});
}, []);
return (
<div className="App">
<div className="welcome">
{state?<><h1>
{state.list[0].main.temp}
<sup> o</sup>C
</h1>
<p>Feels Like {state.list[0].main.feels_like}</p></>:""}
<img src="https://openweathermap.org/img/w/50d.png" alt="haze" />
</div>
</div>
);
}
export default App;

UseEffect is called when the component is completely rendered for the first time, so when you use state.list[0].main.attribute, you're calling an undefined, because your initial state is {}.
Try this:
<div className="welcome">
<h1>
{state.list[0] ? state.list[0].main.temp : ""}
<sup> o</sup>C
</h1>
<p>Feels Like {state.list[0] ? state.list[0].main.feels_like : ""}</p>
<img src="https://openweathermap.org/img/w/50d.png" alt="haze" />
</div>

Related

Why is quizEl returning error 'Cannot read properties of undefined (reading 'map')'

I did a fetch api request then set the value of the question state to the array of objects from API but now when I am using the state it is returning undefined
import React from "react";
function App(props) {
const [question, setQuestion] = React.useState()
const [options, setOptions] = React.useState()
React.useEffect(() => {
fetch('https://opentdb.com/api.php?amount=5&category=18&difficulty=medium&type=multiple').then(res => res.json()).then(value => {
setQuestion(value.results)
})
},
[])
const quizEl = question.map(q => {
return <h3>{q.question}</h3>
})
return (
<>
<div className="question">
{quizEl}
<div className="options">
<button className="btn">option1</button>
<button className="btn">option2</button>
<button className="btn">option3</button>
<button className="btn">option4</button>
</div>
</div>
</>
);
}
export default App;
I tried doing it in useEffects and also directly into the JSX
You need to provide an initial state for your useState :
import React from "react";
function App(props) {
// Here you provide an empty array for your initial state
// (before the api is even called and so before it responses)
const [question, setQuestion] = React.useState([])
const [options, setOptions] = React.useState([])
React.useEffect(() => {
fetch('https://opentdb.com/api.php?amount=5&category=18&difficulty=medium&type=multiple').then(res => res.json()).then(value => {
setQuestion(value.results)
})
},
[])
const quizEl = question.map(q => {
return <h3>{q.question}</h3>
})
return (
<>
<div className="question">
{quizEl}
<div className="options">
<button className="btn">option1</button>
<button className="btn">option2</button>
<button className="btn">option3</button>
<button className="btn">option4</button>
</div>
</div>
</>
);
}
export default App;

Error: Objects are not valid as a React child (found: [object Promise]).….. While getting data from supabase

I am having a problem while getting data from supabase .
Could any one help me
`
import Link from "next/link";
import { supabase } from "../../supabase"
async function Index(){
const { data, error} = await supabase.from("Employees").select("*")
return (
<>
<div className="container flex justify-center">
<h1>Employees</h1>
</div>
{data.map((index) => {
return (
<h1>{index.name}</h1>
)
})}
<Link href="/employees/addemployee">
<h1>Add employee</h1>
</Link>
</>
)
}
export default Index;
`
I tried using map, other function, and looked it up yet nothing works
The problem is how you are fetching the data. Try fetching your data inside an useEffect hook:
import Link from "next/link";
import { supabase } from "../../supabase";
import { useState, useEffect } from "react";
function Index() {
// const { data, error } = await supabase.from("Employees").select("*")
const [data, setData] = useState([]);
const [error, setError] = useState(null);
useEffect(() => {
let cancelFetch = false; // to avoid race conditions on React18
supabase
.from("Employees")
.select("*")
.then((res) => {
if (!cancelFetch) {
setData(res.data);
setError(res.error);
}
});
return () => {
cancelFetch = true;
};
}, []);
return (
<>
<div className="container flex justify-center">
<h1>Employees</h1>
</div>
{data.map((index) => {
return <h1>{index.name}</h1>;
})}
<Link href="/employees/addemployee">
<h1>Add employee</h1>
</Link>
</>
);
}
export default Index;
More info on fetching and useEffect here: https://beta.reactjs.org/apis/react/useEffect#fetching-data-with-effects
Your source code is invalid. React components should always be a function (or class) that returns a react object. it does not accept a promise that returns a react object.
You will probably want to use react's useEffect to solve this problem:
import { useState, useEffect } from "react";
import Link from "next/link";
import { supabase } from "../../supabase"
async function Index(){
const [data, setData] = useState()
const [error, setError] = useState()
useEffect(() => {
supabase.from("Employees").select("*")
.then(data => setData(data))
.catch(err => setError(err))
}, [])
return (
<>
<div className="container flex justify-center">
<h1>Employees</h1>
</div>
{data.map((index) => {
return (
<h1>{index.name}</h1>
)
})}
<Link href="/employees/addemployee">
<h1>Add employee</h1>
</Link>
</>
)
}
export default Index;
Your component cannot be async, because it returns a Promise and React doesn't like that.
There is a cool function on Next.js that allows you to fetch data asynchronously, try that:
function Index({ data }) {
return (
<>
<div className="container flex justify-center">
<h1>Employees</h1>
</div>
{data.map((index) => {
return (
<h1>{index.name}</h1>
)
})}
<Link href="/employees/addemployee">
<h1>Add employee</h1>
</Link>
</>
)
}
export default Index;
export async function getServerSideProps() {
const { data, error} = await supabase.from("Employees").select("*")
return {
props: {
data: data
}
}
}
More here: https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props
Based on the way you are fetching data, I believe you are using next13 and you are in app directory. When you rendered jsx
{data.map((index) => {
return (
<h1>{index.name}</h1>
)
})}
index refers to each element inside the data array. Most likely index.name is an object. that is why it is throwing that error.
console.log("index name",index.name)
If you are using async functional component, you should be using Suspense api. Create a separeate component maybe async Users, fetch the data inside this component, and when you want to display the users inside the Index
import {Suspense} from "react"
function Index(){
return (
<>
....
<Suspense fallback={ <h1>Users are loading...</h1>} >
<Users/>
</Suspense>
....
</>
)
}
You only use async component inside app folder and server component.

Uncaught TypeError: Cannot read properties of undefined (reading 'images')

I'm having this error right after I fix a "Uncaught TypeError: Cannot read properties of undefined (reading 'params')" using const { id } = useParams();.
ProductDetail.jsx
import React, { Fragment, useEffect } from 'react';
import Carousel from "react-material-ui-carousel";
import "./ProductDetails.css";
import {useSelector, useDispatch} from "react-redux";
import { getProductDetails } from '../../actions/productAction';
import { useParams } from 'react-router-dom';
const ProductDetails = ({}) => {
const { id } = useParams();
const dispatch = useDispatch();
const { product, loading, error } = useSelector(
(state) => state.productDetails
);
useEffect(() => {
dispatch(getProductDetails(id));
}, [dispatch, id]);
return (
<Fragment>
<div className="ProductDetails">
<div>
<Carousel>
{product.images && product.images.map((item, i) => (
<img
className='CarouselImage'
key={item.url}
src={item.url}
alt={`${i} Slide`}
/>
))}
</Carousel>
</div>
</div>
</Fragment>
);
};
export default ProductDetails
Console error: sorry its an img, dont know how to post it
product.images && product.images.map((item, i) =>(
on this line product may be undefined. if product is may or may not be present use product?.images?.map
The error is informing you that the product variable is undefined.
Use a null-check/guard-clause to protect it
product && product.images && product.images.map(.....
or use the Optional Chaining operator
product?.images?.map(.....
Since this ProductDetails component appears to be fetching the product data after the component mounts you'll need to guard against product being undefined on the initial render and any subsequent render until the productDetails state is populated. Here it may be preferable to conditionally render null or some loading indicator while product is undefined.
Example:
const ProductDetails = () => {
const { id } = useParams();
const dispatch = useDispatch();
const { product, loading, error } = useSelector(
(state) => state.productDetails
);
useEffect(() => {
dispatch(getProductDetails(id));
}, [dispatch, id]);
return (
<Fragment>
<div className="ProductDetails">
<div>
{product?.images
? (
<Carousel>
{product.images?.map((item, i) => (
<img
className='CarouselImage'
key={item.url}
src={item.url}
alt={`${i} Slide`}
/>
))}
</Carousel>
)
: (
<div>Fetching Product Details</div>
)
}
</div>
</div>
</Fragment>
);
};
export default ProductDetails;

How to create "More" button on React?

I have React components :
Main.jsx
import { useState, useEffect } from "react";
import { Preloader } from "../Preloader";
import { Pokemons } from "../Pokemons";
import { LoadMore } from "../LoadMore";
function Main() {
const [pokemons, setPokemons] = useState([]);
const [loading, setLoading] = useState(true);
const [pokemonsPerPage] = useState("20");
const [pokemonOffset] = useState("0");
useEffect(function getPokemons() {
fetch(
`https://pokeapi.co/api/v2/pokemon?limit=${pokemonsPerPage}&offset=${pokemonOffset}`
)
.then((responce) => responce.json())
.then((data) => {
data.results && setPokemons(data.results);
setLoading(false);
});
}, []);
return (
<main className="container content">
{loading ? <Preloader /> : <Pokemons pokemons={pokemons} />}
<LoadMore />
</main>
);
}
export { Main };
LoadMore.jsx
import React from 'react'
function LoadMore() {
return (
<div className="button_container">
<a class="waves-effect waves-light btn-large" id="more">
More...
</a>
</div>
);
}
export { LoadMore };
I have created a button in the component. After clicking on it, the next 20 elements should be loaded. I created const [pokemonsPerPage] = useState("20"); and const [pokemonOffset] = useState("0"); in order to substitute these values into the request. The first is responsible for the number of objects on the page, the second is responsible for which element to start counting from. That is, now 20 elements are being output, starting from the very first one. (If you change const [pokemonOffset] = useState("0"); to 20, then the output will start from 21 elements). I'm sure that this is necessary for implementation, but I don't know what to do next
Help me complete this functionality
Here is what your Main.jsx should look like.
import { useState, useEffect } from "react";
import { Preloader } from "../Preloader";
import { Pokemons } from "../Pokemons";
import { LoadMore } from "../LoadMore";
function Main() {
const [pokemons, setPokemons] = useState([]);
const [loading, setLoading] = useState(true);
const [pokemonsPerPage] = useState(20);
const [page,setPage] = useState(1);
function getPokemons(pokemonOffset) {
fetch(
`https://pokeapi.co/api/v2/pokemon?limit=${pokemonsPerPage}&offset=${pokemonOffset}`
)
.then((responce) => responce.json())
.then((data) => {
data.results && setPokemons(data.results);
setLoading(false);
});
}
useEffect(() => {
const offset= page*pokemonsPerPage -pokemonsPerPage;
getPokemons(offset);
}, [page]);
return (
<main className="container content">
{loading ? <Preloader /> : <Pokemons pokemons={pokemons} />}
<LoadMore next={()=>setPage(p=>p+1)} />
</main>
);
}
export { Main };
while your Loadmore.jsx
import React from 'react'
function LoadMore(next) {
return (
<div className="button_container">
<a type="button" onclick={next} class="waves-effect waves-light btn-large" id="more">
More...
</a>
</div>
);
}
export { LoadMore };

how to show loader in react . using hooks

I am using axios for communicate with server.I want to show loader when user request to server and hide the loader when request is complete
So i make a custom component to do this task .but my UI hang when I click multiple times on same button
const Loader = () => {
const { loadingCount } = useLoadingState(),
{showLoading, hideLoading} = useLoadingActions();
useEffect(()=>{
const self = this
axios.interceptors.request.use(function (config) {
showLoading();
return config
}, function (error) {
return Promise.reject(error);
});
axios.interceptors.response.use(function (response) {
// spinning hide
// self.props.loading(false)
hideLoading()
return response;
}, function (error) {
hideLoading();
return Promise.reject(error);
});
})
return (
<div>
{loadingCount > 0 ?<div style={{position:"fixed",display:"flex",justifyContent:"center",alignItems:"center",width:'100%',height:'100%',zIndex:999999}}>
{/*{loadingCount > 0 ? */}
<Spin tip="Loading..." style={{zIndex:999999}}></Spin>
{/*: null}*/}
</div>: null}
</div>
);
};
Problem is on useeffect
when I comment out useEffect code it works perfectly .
NoTe : showloading and hideloading increase and decrease the loading count.
I think I have deallocate axios object the when component is unmount.???
Add empty array to sencod parameter to useEffect.
It works like componentDidMount() in functional component.
const { useState, useEffect } = React;
const Counter = () => {
const [count, setCount] = useState(0)
const [isLoaded, setIsLoaded] = useState(false);
useEffect(() => {
setTimeout(() => {
setIsLoaded(true);
}, 3000);
}, []); // here
return (
<div>
{
isLoaded &&
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
}
</div>
)
}
ReactDOM.render(<Counter />, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.7.0-alpha.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.7.0-alpha.2/umd/react-dom.production.min.js"></script>
<div id="app"></div>
i usualy use this code to show loading when request data is processing and hide when it's done
const Loader = () => {
const {data, setdata} = useState([])
useEffect(()=>{
axios.get('your host').then(res => {
setdata(res.data);
}).catch(err => {
setdata(res.data);
}
});
return (
<div>
{data.length > 0
?
<div style={{position:"fixed",display:"flex",justifyContent:"center",alignItems:"center",width:'100%',height:'100%',zIndex:999999}}> </div>
:
<Spin tip="Loading..." style= {{zIndex:999999}}>
</Spin>
</div>
);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
First I created Loading components in shared folder. I am using Daisy UI, that's why you have to first install tailwind & daisy otherwise it will not work. My Loading Code:
import React from 'react';
const Loading = () => {
return (
<div className="flex items-center justify-center ">
<div className="w-16 h-16 border-b-2 border-gray-900 rounded-full animate-spin"></div>
</div>
);
};
export default Loading;
Then I am using this Loading component in my Allproduct component. For viewing Loading i created Reload useState.You will see below in my code, that will help my loader show when fetching time is very long.
import React, { useEffect, useState } from 'react';
import Loading from '../Shared/Loading';
import AllProduct from './AllProduct';
const AllProducts = () => {
const [products, setProduct]=useState([])
const [Reload, setReload] = useState(true);
useEffect(()=>{
fetch('https://stormy-hamlet-97462.herokuapp.com/products/')
.then(res=>res.json())
.then(data=>{setProduct(data)
setReload(false)})
},[])
if(Reload){
return <Loading></Loading>
}
return (
<div>
<h4 className='text-4xl text-primary text-center sm:w-full px-32 mx-5
lg:my-12 '>All Products</h4>
<div className='grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5'>
{
products.map(product=><AllProduct key={product._id} product={product} ></AllProduct>)
}
</div>
</div>
);
};
export default AllProducts;

Categories

Resources