Undefined is not an object React native - but displays data afterwards - javascript

I keep this error Undefined is not an object(evaluating ....), I find it funny, because I get the object when i make a correction and it refreshes, but when i open a app at first, i get the error, So i delete the part that has the error then the app loads, i then bring back the delete part, it will show correctly. Please help, Im just learning react.
Im not sure but i think there is a method that makes my app wait when it fetches the data, then its loads, rather than just load at first nonetheless...
This is my code please.
function ExploreScreen() {
const getListingsApi = useApi(client.get(endpoint));
useEffect(() => {
getListingsApi.request();
}, []);
return ({getListingsApi && <Text>{getListingsApi.data[0].latitude}</Text>}) -this is the part i delete and bring back to ake it display.
I removed the parts that are working. This is just a brief version of the code, below is my useAPI hook
import { useState } from "react";
export default useApi = (apiFunc) => {
const [data, setData] = useState([]);
const [error, setError] = useState(false);
const [loading, setLoading] = useState(false);
const request = async (...args) => {
setLoading(true);
const response = await apiFunc(...args);
setLoading(false);
setError(!response.ok);
setData(response.data);
return response;
};
return { data, error, loading, request };
};

It's hard without a reproducible example, but I would guess that data[0] might be the culprit:
return ({getListingsApi && <Text>{getListingsApi.data[0].latitude}</Text>})
The collection is being initialized to [] (in the hook via const [data, setData] = useState([]);) which means it won't have a first element.
This would explain why adding it later, would not cause an exception, since at that point, the data will already be loaded and the array will have been initialized.
Consider trying something like this:
return (
{getListingsApi && getListingsApi.data.length > 0 && (
<Text>{getListingsApi.data[0].latitude}</Text>
)}
)

Related

React cannot read properties of array undefined while using use location hook

I am trying to pass some data from one page to the other in react using the useNavigate and useLocation hook.The data is transferring fine and i am recieving it in the next component as shown below:
// sending component
const handleNavigate = () => {
navigate('/updateBlogPost', { state: { blogPost } });
};
//recieving component
const location = useLocation();
const [title, setTitle] = useState(location.state.blogPost.title);
const [description, setDescription] = useState(location.state.blogPost.description);
const [categories, setCategories] = useState(location.state.blogPost.categories);
const [content, setContent] = useState(location.state.blogPost.content);
Now I am facing the problem with the category array because it becomes undefined when the page first renders and i get the following error:
Uncaught TypeError: Cannot read properties of undefined (reading 'map')
I can get rid of the error using optional chaining but how to get the data of the array when it is available.
I tried setting it in the use effect but it does not seems to work can any one suggest some better way?
use useEffect to get data when its available based on dependencies of "location" changes everytime it will fire it after every completed render.
const [categories, setCategories] = useState([]);
useEffect(() => {
if(location.state.blogPost.categories)
setCategories(location.state.blogPost.categories)
},[location])

Why does my useEffect() fetch data unreliably. I cannot map through the data because I am getting some undefined responses - ReactJS

I have a sidebar which sets a category Id on click and shows product information based on this Id.
In order to display each product's details, I make an api post call using axios in a useEffect() hook and setData with useState hook.
However, when I try to console.log the data, I get unreliable data back, that is, some undefined and some data.
import { useState, useEffect, useCallback, useMemo } from "react";
import axios from "axios";
import ProductCard from "../Product-cards/_medium-product-card";
const ProductDisplay = ({ subCategorySkus, categoryId, allSkus }) => {
const [data, setData] = useState();
const [isLoading, setIsLoading] = useState();
const apiRequest = { product_skus: allSkus };
const productData = useProductData(apiRequest);
useEffect(() => {
const fetchData = async () => {
try {
const response = await axios.post("/products", apiRequest);
setData(response.data);
setIsLoading(false);
} catch (err) {
console.log(err.message);
}
};
fetchData();
}, [categoryId]);
console.log(data);
return isLoading ? (
" data is loading ..."
) : (
<div className="product-display">
<h3>Child component Id: {categoryId}</h3>
<ProductCard categoryId={categoryId} />
</div>
);
};
export default ProductDisplay;
You can see here what I get in the console:
.
I have tried adding an if condition, but I am not sure that addresses the issue. I have tried with different dependencies in the useEffect. But I feel there is something I am not understanding.
The api is sending the information correctly, but I get several responses in the console.log and some of them come in as undefined.
This means that I can do a data.map because it crashes the component.
Any help?
UPDATE:
#moonwave99 provided the answer (see below). For the benefit of others who may browse through this question and to clarify what the solution entails, I am including an image below, showing where I changed my code. I think that most importantly, I had not initialised my useState() to an empty array, like this: useState([]).
Any further clarification of the issues here by anyone who knows more, is welcomed. As this is only a quick fix without enough context to understand the logic.

Why is useState() not setting the default value?

I have created following reactComponent. From what I understand useState([]); should set the comments variable to an array. But it does not. I get an exeption that I Try to run .map() on an object. What I have to do is Object.values(comments) to make it work but I don't understand why. My api definetly returns an array of comment objects.
import React, { useState, useEffect } from 'react';
import axios from 'axios';
export default ({ postId }) => {
const [comments, setComments] = useState([]);
const fetchData = async () => {
const res = await axios.get(
`http://localhost:4001/posts/${postId}/comments`
);
setComments(res.data);
};
useEffect(() => {
fetchData();
}, []);
const renderedComments = comments.map(comment => {
return <li key={comment.id}>{comment.content}</li>;
});
return <ul>{renderedComments}</ul>;
};
Your use of state is correct as far as I can tell, the fact that Object.values works on the data handed back to you implies it is definitely either an object or an array, have you run Array.isArray(res.data) as part of your troubleshooting process?
As stated by a commenter above, the most likely scenario is that you are getting an object back from your back end. Other things you can do to confirm its the data handed back to you at fault would be to simply comment out your useEffect and see if it still throws the same exception.

trying to get config from backend to react front-end

Am trying to make a script that easy to edit for users from the back-end, so they won't need to re-build the react app each time they edit something (such as color, phone number etc)
so i make a call to the back-end by axios
let config={};
(async () => {
try {
config = await axios.get("http://localhost:8000/settings");
config = config.data;
} catch (e) {
alert(e);
}
})();
const App = () => {
let show;
///
const [name, setName] = useState("");
const [inchat, setInchat] = useState(false);
const { t, i18n } = useTranslation();
///settings
const [direction, setDirection] = useState("text-left");
const [socket] = useState(openSocket(config.url || '/'));
console.log(socket)
const [settings] = useState(config);
as you see, after loading the config file from back-end, am using it here in front-end.
the problem is that sometimes the App component load first, and the script throw error of config undefind, how can i make the script http request lunch first, i tried to put the http request inside a useEffect hook but still the same problem.
thank you
This is how I usually implement things when it comes to http requests.
This is assuming that you're not using Server Side Rendered (SSR) service like Next.js, where you want the data to be fetched before the page is even rendered, then you would use a different approach.
Otherwise you could show a loading animation or just show a blank screen until the data is loaded.
Click the "Run code snippet" button below to see it work.
// main.js
const { useState, useEffect } = React;
const App = () => {
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [data, setData] = useState(null);
useEffect(() => {
/*
StackOverflow not letting me do async/await so doing a promise
*/
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(response => response.json())
.then(json => {
setData(json);
setLoading(false);
})
.catch(error => {
console.log('ERROR', error);
setError(error);
setLoading(false);
});
}, []);
return <div>
{loading
? <p>Loading...</p>
: <div>
{error
? <div>{JSON.stringify(error)}</div>
: <div>Loaded <br />{JSON.stringify(data)}</div>
}
</div>}
</div>
}
ReactDOM.render(<App />, document.querySelector('#root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Since the call to your API is async you will need to wait for the call to be finished to show your app, useEffect is a good way to do it, but you will need to make some changes in your code to work.
I see that you are handling all the state variables separately but some of them depend on each other, for this cases is better to use an object so you can be sure all the properties are updated at the same time and also to know if you have already the needed data to show your app
// show your app until this is not null
const [state, setState] = useState(null);
// set all the state variables at the same time
useEffect(() => { axios.get(url).then(config => setState(config)) })
if(!state) return <div>Loading...</>
return <div>App</div>
Another alternative is to use another state variable to control if you should show your app or not
// all your state variables
const [state, setState] = useState(null);
.
.
const [isLoading, setIsLoading] = useState(false);
// set all the state variables at the same time
useEffect(() => {
setLIsLoading(true);
axios.get(url).then(config => {
setIsLoading(false);
setState(config);
)
})
if(isLoading) return <div>Loading...</>
return <div>App</div>

How to insert setState value into useEffect hook?

I watched a Youtube video and I made my own recipe app. I'm a beginner at React.js and I've been solving this problem for about 2 days. Seems that i cant pass the value of my state to useEffect hook. Here's an example of my code. The error says
"React Hook useEffect has a missing dependency: 'query'. Either include it or remove the dependency array" and everytime I typed in the input box it triggers the useEffect hook. Thank you and your help is very much appreciated.
const [recipes, setRecipes] = useState([]);
const [search, setSearch] = useState('');
const [query, setQuery] = useState('steak');
const updateSearch = e => {
setSearch(e.target.value);
console.log(search)
}
const getSearch = e => {
e.preventDefault();
setQuery(search);
}
useEffect(() => { // error Is from the Query variable
const GetRecipe = async () => {
const APP_ID = "3834705e";
const APP_KEY = "c23e9514f82c2440abf54b21edd4c3dc";
const res = await fetch(`https://api.edamam.com/search?q=${query}&app_id=${APP_ID}&app_key=${APP_KEY}`);
const data = await res.json();
setRecipes(data.hits);
}
GetRecipe();
},[getSearch]) //this triggers everytime I typed in the input box which is not it is supposed to
return(
<div className='recipelist'>
<form onSubmit={getSearch}>
<input type="search" onChange={updateSearch}/>
<button type='submit'>submit</button>
</form>
As the error tells you, when using a useEffect hook, that hook can receive two arguments, the first one is the handler effect and the second one is an array containing all dependencies that effect will use, so as you are using the query state into the http url, you need to pass that dependency into the array, so could be something like this.
useEffect(() => { // error Is from the Query variable
const GetRecipe = async () => {
const APP_ID = "3834705e";
const APP_KEY = "c23e9514f82c2440abf54b21edd4c3dc";
const res = await fetch(`https://api.edamam.com/search?q=${query}&app_id=${APP_ID}&app_key=${APP_KEY}`);
const data = await res.json();
setRecipes(data.hits);
}
GetRecipe();
},[getSearch, query])
so what is actually doing the array dependency, as React docs says, array dependency it's used to check if the effect should execute again based on its dependencies, so in your code everything you type something, getSearch method is re-creating again and again in memory, so it will check the last getSearch function that it took and compare it with the new ones, so it will check as equally checker like fn1 === fn2, so due to both function are exactly the same, both keeps different space in memory, so both are different objects, check this docs to understand the concept.
Here you have the react docs too

Categories