get array from single firestore document with ReactJs - javascript

I'm learning to use firebase and react. I have shared my firestore collection image. and my code for fetching the array from my document is given below.
This code is fetching the data from my firestore database and then storing the result in my watchlistMovies react state. when i try to log the react state or even data.data() it gives the desired result but when i try to map over the array or do something similar like logging watchlistMovies.myList[0].media_type it hits me with an error. i tried my best trying different things making it work but it breaks a thing or two in process.
I hope someone here will help me. Thank you in advance! : )
updated the code
const Watchlist = () => {
const [watchlistMovies, setwatchlistMovies] = useState([]);
const {currentUser} = useAuth()
const usersCollectionRef = collection(db,"users")
const docRef = doc(db,"users",currentUser.uid)
useEffect(() => {
const getWatchListMovies = async () => {
const data = await getDoc(docRef)
if (data.exists()) {
console.log(data.data());
setwatchlistMovies([...watchlistMovies ,data.data().myList])
} else {
console.log("empty");
}
}
getWatchListMovies();
}, [])
console.log(watchlistMovies);
// console.log(watchlistMovies.myList[0]);
return (
<div className="content-page-area">
<h1 className="trending-text"> My Watchlist </h1>
<Container className="watchlist-container">
<hr/>
{watchlistMovies.map(
(item) => (
<ListContent
item_poster={item.poster_url}
item_title={item.media_title}
item_year={item.release_year}
item_rating={item.media_rating}
item_type={item.media_type}
item_id={item.media_id}
/>
)
)}
</Container>
<br/>
<br/>
<br/>
</div>
)
}
export default Watchlist

Related

How do you catch if an incoming object (from a http request) doesn't have a certain array? (React JS)

I'm fetching an object (with a text value and a few arrays) from an API and transferring those to local variables for use. All is working except for when that object I'm fetching doesn't have one of those arrays and I try to use it the whole site crashes. I'm lost on how to do the error handling here.
import React, { useEffect, useState } from 'react'
import classes from './Streaming.module.css'
const Streaming = (props) => {
const [streamingOn, setStreamingOn] = useState(false)
const [streamingData, setStreamingData] = useState(null)
async function receiveStreaming() {
await fetch(`https://api.themoviedb.org/3/movie/${props.movie}/watch/providers?
api_key=35135143f12a5c114d5d09d17dfcea12`)
.then(res => res.json())
.then(result => {
setStreamingData(result.results.US)
setStreamingOn(true)
}, (error) => {
console.error("Error: ", error)
}
)
// console.log(data)
}
const displayStreaming = streamingData => {
let sortedData = { ...streamingData }
let streamData = sortedData.flatrate
let rentData = sortedData.rent
let linkText = streamingData.link
let id = Math.random()
let streamListItems = streamData.map((movie) =>
<li key={id}>
<a href={linkText}><img className={classes.logoimg} src=. {'https://image.tmdb.org/t/p/w500/' + movie.logo_path}></img></a>
</li>)
let rentListItems = rentData.map((movie) =>
<li key={id}>
<a href={linkText}><img className={classes.logoimg} src={'https://image.tmdb.org/t/p/w500/' + movie.logo_path}></img></a>
</li>)
return (
<React.Fragment>
<p>Stream on</p>
<ul className={classes.logolist}>{streamListItems}</ul>
<p>Rent on</p>
<ul className={classes.logolist}>{rentListItems}</ul>
</React.Fragment>
)
// console.log(sortedData)
}
return (
<React.Fragment>
<button onClick={receiveStreaming}></button>
{<div className={classes.streaminglogos}>
{(streamingOn) && <div>{displayStreaming(streamingData)}</div> }
</div>}
</React.Fragment>
)
}
export default Streaming
Use optional chaining to check the expected array has been received or not.
Assuming that you need to show an error UI when the expected array was not received, then you can set a flag(isErrored) to true and render that conditionally.
Handling Response JSON
if (!result?.results?.US) {
setIsErrored(true);
} else {
setStreamingData(result.results.US)
setStreamingOn(true);
}
Rendering Error UI conditionally
{isErrored && (<ErrorUI />)}
There are a few things you can do here. The first is that you could check if the array exists when you first get it and then append it on to it if it doesn't.
Maybe something like:
if(!result.results.US){
result.results.US = []
}
Or you could check if the array exists when you are displaying the data by conditionally rendering the component (or piece of component). If the data does not have the array (using the above method) don't display it.
Hope this helps!

Reactj.s: Item deleted only after refresh | Delete Method

I'm trying to send a delete request to delete an item from an API.
The API request is fine when clicking on the button. But Item get's deleted only after refreshing the browser!
I'm not too sure if I should add any parameter to SetHamsterDeleted for it to work?
This is what my code looks like.
import React, {useState} from "react";
const Hamster = (props) => {
const [hamsterDeleted, setHamsterDeleted] = useState("")
async function deleteHamster(id) {
const response = await fetch(`/hamsters/${id}`, { method: "DELETE" });
setHamsterDeleted()
}
return (
<div>
<p className={props.hamster ? "" : "hide"}>
{hamsterDeleted}
</p>
<button onClick={() => deleteHamster(props.hamster.id)}>Delete</button>
<h2>{props.hamster.name}</h2>
<p>Ålder:{props.hamster.age}</p>
<p>Favorit mat:{props.hamster.favFood}</p>
<p>Matcher:{props.hamster.games}</p>
<img src={'./img/' + props.hamster.imgName} alt="hamster"/>
</div>
)
};
export default Hamster;
<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>
Imagine you have a parent component (say HamstersList) that returns/renders list of these Hamster components - it would be preferable to declare that deleteHamster method in it, so it could either: a) pass some prop like hidden into every Hamster or b) refetch list of all Hamsters from the API after one got "deleted" c) remove "deleted" hamster from an array that was stored locally in that parent List component.
But since you are trying to archive this inside of Hamster itself, few changes might help you:
change state line to const [hamsterDeleted, setHamsterDeleted] = useState(false)
call setHamsterDeleted(true) inside of deleteHamster method after awaited fetch.
a small tweak of "conditional rendering" inside of return, to actually render nothing when current Hamster has hamsterDeleted set to true:
return hamsterDeleted ? null : (<div>*all your hamster's content here*</div>)
What do you want to do in the case the hamster is deleted? If you don't want to return anything, you can just return null.
I'm not too sure if I should add any parameter to SetHamsterDeleted for it to work?
Yes, I'd make this a boolean instead. Here's an example:
import React, { useState } from "react";
const Hamster = (props) => {
const [hamsterDeleted, setHamsterDeleted] = useState(false);
async function deleteHamster(id) {
const response = await fetch(`/hamsters/${id}`, { method: "DELETE" });
setHamsterDeleted(true);
}
if (hamsterDeleted) return null;
return (
<div>
<p className={props.hamster ? "" : "hide"}>
{hamsterDeleted}
</p>
<button onClick={() => deleteHamster(props.hamster.id)}>Delete</button>
<h2>{props.hamster.name}</h2>
<p>Ålder:{props.hamster.age}</p>
<p>Favorit mat:{props.hamster.favFood}</p>
<p>Matcher:{props.hamster.games}</p>
<img src={'./img/' + props.hamster.imgName} alt="hamster"/>
</div>
);
};
HOWEVER! Having each individual hamster keep track of its deleted state doesn't sound right (of course I don't know all your requirements but it seems odd). I'm guessing that you've got a parent component which is fetching all the hamsters - that would be a better place to keep track of what has been deleted, and what hasn't. That way, if the hamster is deleted, you could just not render that hamster. Something more like this:
const Hamsters = () => {
const [hamsers, setHamsters] = useState([]);
// Load the hamsters when the component loads
useEffect(() => {
const loadHamsters = async () => {
const { data } = await fetch(`/hamsters`, { method: "GET" });
setHamsters(data);
}
loadHamsters();
}, []);
// Shared handler to delete a hamster
const handleDelete = async (id) => {
await fetch(`/hamsters/${id}`, { method: "DELETE" });
setHamsters(prev => prev.filter(h => h.id !== id));
}
return (
<>
{hamsters.map(hamster => (
<Hamster
key={hamster.id}
hamster={hamster}
onDelete={handleDelete}
/>
))}
</>
);
}
Now you can just make the Hamster component a presentational component that only cares about rendering a hamster, eg:
const Hamster = ({ hamster, onDelete }) => {
const handleDelete = () => onDelete(hamster.id);
return (
<div>
<button onClick={handleDelete}>Delete</button>
<h2>{hamster.name}</h2>
<p>Ålder:{hamster.age}</p>
<p>Favorit mat:{hamster.favFood}</p>
<p>Matcher:{hamster.games}</p>
<img src={'./img/' + hamster.imgName} alt="hamster"/>
</div>
);
};

React component not rendering despite event firing

I'm making a blog with react, next.js, and json-server. I have come as far as dynamically loading blog posts and other UI, but now when I'm trying to load the comments dynamically as well, it's not working.
The component in question is this one.
const Comments = ({ id }) => {
const [com, setCom] = useState([]);
useEffect(() => {
const getComments = async () => {
const comment = await fetchPost(id);
if (comment["comments"].length == 0) return;
const comments = [...comment["comments"]];
setCom([...comment["comments"]]);
};
getComments();
}, []);
return (
<div>
{com.map((p) => {
console.log(p.comment);
<Comment key={p.id} comment={p.comment} />;
})}
</div>
);
};
I know that the component is getting called and have the information as I'm logging it to console inside map. What I can't get my head around is why it is not rendering as it is a near carbon copy of how I render the blog-posts.
Aside from the above, I have tried the following:
checked syntax
Running <Comment/> with and without a key
putting in strings directly inside the component com.map, instead of p.comment == does not render
lifting state and useEffect up to <Post/>
Your function is not returning anything so React has nothing to render
{com.map((p) => (
<Comment key={p.id} comment={p.comment} />;
))}
The following code returns nothing
() => { const value = 1; }
The following code returns 1
() => { const value = 1; return value;}
The following code returns 1
() => 1

Sort Data Using Time Value in Realtime Database using React-js

I am trying to sort my Firebase Data based on the Time it was created on such that the entry created last should come on the top.
Below is my code for the same,
import React, { useEffect, useState } from 'react'
import fire from './fire1';
export const Weight = () => {
const[input, setInput] = useState("")
const[weightList, setWeightList] = useState("")
const handleOnSubmit = () =>{
const dataRef = fire.database().ref('Tushar');
const data = ({
input,
time : new Date().toLocaleTimeString()
});
dataRef.push(data)
console.log(dataRef.orderBy('currTime').get())
}
useEffect(()=>{
const dataRef = fire.database().ref('Tushar');
dataRef.on('value', (snapshot)=>{
var weight = (snapshot.val())
var weightList = []
for (let id in weight){
weightList.push(weight[id])
}
setWeightList(weightList)
})
},[])
return (
<div>
<input
type = "text"
placeholder = "Enter Your Weight"
value = {input}
onChange = {(e)=> setInput(e.target.value)}
/>
<button onClick = {handleOnSubmit} >Submit</button>
{weightList? weightList.map((val, index) =>{
return(
<div key = {index} >
<h1>{val.input}</h1>
<i>{val.time}</i>
</div>
)
}): "" }
</div>
)
}
When I am trying to use the OrderBy() Function
It is showing the following error.
TypeError: dataRef.orderBy is not a function
Do let me know if I am committing any error or missing some piece of information.
Firebase real time database documentation
read the data section
The query you are trying to use is of firebase firestore database and not realtime database,
These are the queries for realtime database
orderByChild() : Order results by the value of a specified child key or nested child path.
orderByKey() : Order results by child keys.
orderByValue() : Order results by child values.

Trying to map on React

I added the Nutrition file
const Nutrition = () => {
return(
<div>
<p>Label</p>
<p>Quantity</p>
<p>Unit</p>
</div>
)
}
export default Nutrition
I'm trying to map something in React but I'm getting this error map is not function. I'm trying to fetch an Api and now I'm trying to map another component to it, but the error is still there. Could someone help me or give me a hint
const ApiNutrition = () => {
const [nutritions, setNutritions] = useState([])
useEffect( () => {
getNutritions();
}, [])
const getNutritions = async () => {
const response = await fetch(`https://api.edamam.com/api/nutrition-data?app_id=${API_ID}&app_key=${API_KEY}&ingr=1%20large%20apple`)
const data = await response.json();
setNutritions(data.totalNutrientsKCal)
console.log(data.totalNutrientsKCal);
}
return(
<div>
<form className="container text-center">
<input classname="form-control" type="text" placeholder="CALORIES"/>
<button classname="form-control" type="submit">Submit</button>
</form>
{nutritions.map(nutrition => (
<Nutrition />
))}
</div>
)
}
export default ApiNutrition
From your code, I can see you have two places where you are setting the value of nutritions. One is while defining with useState(), and the other is after API call with setNutritions.
The error you are getting is map is not a function, it means somehow type of nutritions is not an array.
while defining with useState you are providing [] as default value so it means the error is with the API, the response you are getting from API which you are passing to setNutritions is not an array.
You can debug the API response type by typeof data.totalNutrientsKCal inside console.log

Categories