Problem occurs when use find function in React - reactjs

I am new to react and I try to get data from the backend and view that data in the frontend. To do that I tried this code:
function VProfile() {
const buyerId=(localStorage.getItem("userId"));
console.log(buyerId);
const [buyerDetails, setBuyerDetails] = useState({});
useEffect(() => {
axios
.get(`/getBuyerDetails`)
.then((response) => setBuyerDetails(response.data.existingBuyers))
.catch((err) => console.error(err));
}, []);
console.log(buyerDetails);
const oneBuyer = buyerDetails?.find(oneBuyer => oneBuyer.buyerId === buyerId);
console.log(oneBuyer);
}
When I call the API I get a length 3 array of objects. This is an image of the data.
Then I try to find the data of a specific buyer using the find function. To do that I use this const oneBuyer = buyerDetails?.find(oneBuyer => oneBuyer.buyerId === buyerId) code. But then I got an error that says TypeError: buyerDetails.find is not a function. How do I silve this problem?
Thank You!

You initialize the state with an object ({}):
const [buyerDetails, setBuyerDetails] = useState({});
Objects don't have .find, only arrays do.
You might want to initialize it to an empty array ([]), or undefined to more clearly signal the case that the data is not yet loaded.

You call setBuyerDetails asynchronously, so at the moment when you log them, the data hasn't arrived, due to console.log you are being "deceived" to believe the data is there. From docs:
Please be warned that if you log objects in the latest versions of
Chrome and Firefox what you get logged on the console is a reference
to the object, which is not necessarily the 'value' of the object at
the moment in time you call console.log(), but it is the value of the
object at the moment you open the console.
To avoid that error you can initialize that variable with empty array initially:
const [buyerDetails, setBuyerDetails] = useState([]);

Do it something like that and initialize with an array and you are using async operations so please add the loading flag
function VProfile() {
const buyerId=(localStorage.getItem("userId"));
console.log(buyerId);
const [buyerDetails, setBuyerDetails] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
axios
.get(`/getBuyerDetails`)
.then((response) => {
setBuyerDetails(response.data.existingBuyers));
setLoading(false);
})
.catch((err) => console.error(err));
}, []);
console.log(buyerDetails);
if (loading) return <p>loading....</p>
const oneBuyer = buyerDetails?.find(oneBuyer => oneBuyer.buyerId === buyerId);
console.log(oneBuyer);
}

Related

React.js Object fetched into Context from Firestore is undefined, when using it in another component

I am facing a problem, as I am trying to use variable, which is being fetched in Context. And it's not a first time I had this problem, so seems like I am missing some crucial concept in React.
In my Context I am fetching object from firestore and setting it as a state. I worked with this fetched object before, so I know that problem is not in fetching or object structure.
const [products, setProducts] = useState([])
const [filteredProducts, setFilteredProducts] = useState([])
useEffect(() => {
const getCategoriesMap = async () => {
const categoryMap = await getCategoriesAndDocuments('categories')
const all = await Object.values(categoryMap).reduce((acc, arr) => acc.concat(arr), [])
setProducts({ all, ...categoryMap })
}
getCategoriesMap()
setFilteredProducts(products['all'])
}, [])
But as I am trying to use state with this object in another component - I get error 'Cannot read properties of undefined'.
For example here:
const { products } = useContext(ProductsContext)
const newCollection = products?.all?.filter(product => product.new === true)
Or here:
const maxSteps = newCollection?.length
return (
<div className='new-img' style={{ backgroundImage:`url(${newCollection[activeStep]?.imgUrl})` }}></div>
)
Could somebody tell me the reason why the state is undefined, or even better provide with some useful links to read on this topic.

Axios returns object but useState hook wont set

Ive searched for problems like this but haven't found solution yet. When I console.log(data) I see the object with all the proper data. When i try to access it with data.name(or any other property on the object) nothing happens, even intellisense doesn't have anything for it.
const key = process.env.REACT_APP_WEATHER_API_KEY;
const [data, setData] = React.useState<{}>({});
const url = `https://api.openweathermap.org/data/2.5/weather?q=Lethbridge&units=imperial&appid=${key}`;
const getWeatherData = async () => {
if (longitude && latitude !== undefined) {
axios
.get(url)
.then(response => {
const returnedData = response.data;
setData(returnedData);
})
.catch(err => console.log('Error:', err));
}
};
React.useEffect(() => {
getWeatherData();
console.log('data', data);
}, []);
When i console.log('data') though i see the object returned from api request proper like this.
Console logged return from api
You are fetching some data that is not typed (or at least you are not using the type in your code. You are getting data from axios that is typed as any, because axios doesn't know anything about its type. Now when you use that data to set it to the state with setData, the data will take the type you have given to the state, in this case {}, an empty object, hence why you can't access any properties.
You need to shape that object, declare a type for the data you are receiving and set it to the state. If you declare the state like this, you will be able to access the property name:
const [data, setData] = React.useState<{name: string}>({});

after axios get my setState hooks doesn't run

I have a lot of functions like this, using the same approach, and they all run fine.
But this one is going me crazy.
My code is:
const [match,setMatch] = useState(null);
axios.get(path)
.then((res) => {
status = res.data;
setMatch(res.data)});
const test = match;
If I debug the program and break at setMatch(status), the content of res.data is correct:
res.data is an array, and each element contains a mix of values and objects as show in the screenshot below.
But when I execute the setMatch(status) the result is that the match state variable doesn't change: it remains null as set the first time.
Can someone provide some suggestion?
From your question, I dont know what could likely affect your code from running. But this is the common pattern when handling asynchronous request.
It is expected that it should be executed in the useEffect hook right after it is painted
const Component = () => {
const [match,setMatch] = useState([]);
useEffect(() => {
axios.get(path)
.then((res) => {
status = res.data;
setMatch([match, ...res.data])})
.catch((err) => handleError(err));
}, [path]) // assuming that the path changes otherwise if you are running this once, leave the array empty
return (<div> {(match.length > 0)? 'Loading': {renderYourLogicHere} </div>)
}

Setting state inside a promise inside a useEffect hook in React

I've been trying to figure out why my code doesn't work for an hour now. So basically I want to fetch some data from a MySQL database, my serverside code is working as expected but whenever I try to fetch it in the client with the following code setting the state fails:
const [data, setData] = useState(null);
useEffect(() => {
const loadData = () => {
fetch("http://localhost:5000/getusers")
.then((response) => response.json())
.then((data) => {
setData(data); // data is undefined but when consoled-out it's in proper form
});
};
loadData();
console.log(data);
}, [data]);
data is an array of objects. I assume I can't pass setState in a promise because I've added a conditional for rendering the data so even if it's null it just won't render but I receive a TypeError: data.map is not a function (it would be great if someone could explain how this happens).

Updated array needs to be set with react hooks but creates infinite loop

in my code below I am fetching images from Firebase Firestore. The url is returned properly and is pushed to the images state
Now the problem is that identical urls are being added (because the useEffect runs to soon or early?)
So in the second useEffect i update the images array and remove duplicates nice and easy with ...new Set, but the problem is that setImages() is also called there which is not allowed since this creates the infinite loop.
So my question is, can someone tell me where to set the updated array uniq to the images state the right way?
Thanks in advance!
const [evtsFiltered, setEvtsFiltered] = useState([])
const [images, setImages] = useState([])
useEffect(() => {
evtsFiltered?.map((item) => {
storageRef
.child(item)
.getDownloadURL()
.then((url) => {
setImages((images) => [...images, url]) // url returns a plain string such as 'http://image-1.png'
})
})
}, [evtsFiltered])
useEffect(() => {
let uniq = [...new Set(images)] // Duplicates are removed
setImages(uniq) // Infinite loop problem
}, [images])
Improvements needed in your code:
You don't need to use optional-chaining with evtsFiltered because its initial value is an empty array.
map() is not the right method to use if you are just going to iterate over the array. You could use map() method along with Promise.all() to fetch image URLs.
Identical URLs could not be because of useEffect hook. Either you have duplicate URLs in the firebase storage or you are not updating the state correctly.
You wouldn't need the second useEffect hook if you update the images state correctly in the first useEffect hook.
Try updating the state using Promise.all() and map() method as shown below:
useEffect(() => {
const arr = evtsFiltered.map((item) => {
return storageRef.child(item).getDownloadURL();
});
Promise.all(arr)
.then(urls => {
setImages(urls);
})
.catch(err => /* handle error */ );
}, [evtsFiltered]);
Using map() method, create an array of promises that you can then resolve using Promise.all() method. Also, remove the 2nd useEffect hook.
It's because you try to update state on which you listen tov updated. One solution is to create another state which contains unique images.
const [evtsFiltered, setEvtsFiltered] = useState([])
const [images, setImages] = useState([])
const [uniqueImages, setUniqueImages] = useState([])
useEffect(() => {
evtsFiltered?.map((item) => {
storageRef
.child(item)
.getDownloadURL()
.then((url) => {
setImages((images) => [...images, url]) // url returns a plain string such as 'http://image-1.png'
})
})
}, [evtsFiltered])
useEffect(() => {
let uniq = [...new Set(images)] // Duplicates are removed
setUniqueImages(uniq) // Infinite loop problem
}, [images])
Another to set unique images just in first effect.
.then((url) => {
setImages((images) => [ ...new Set([ ...images, url])]) // url returns a plain string such as 'http://image-1.png'
})

Resources