Using nested routing in Next to get data from Firestore - javascript

I want to get data from Firestore in Next.JS like Reddit. For example (http://localhost:3000/r/BestBurger) in cloud firestore my data is in (/BestBurger/posts/posts/KrcvgXMX4HyNKPD1kRAR)
import { useRouter } from 'next/router';
import { useState, useEffect } from 'react';
import firebase from '../../firebase/clientApp';
import Card from '../../components/card/Card';
;
export default function Page() {
const router = useRouter();
const { page } = router.query;
function usePosts() {
const [posts, setPosts] = useState([])
useEffect(() => {
firebase
.firestore()
.collection(`${page}`).doc('posts').collection('posts')
.onSnapshot((snapshot) => {
const newPosts = snapshot.docs.map((doc) => (
{
id: doc.id,
...doc.data()
}))
setPosts(newPosts)
}
)
}, [])
return posts;
}
const posts = usePosts()
console.log(posts)
return (
<>
{
posts.map((post) => (
<Card key={post.id}>
<h2>{post.title}</h2>
{post.body}
</Card>
))
}
</>
)
}
Again, I want to get my page route to the .collection()

Related

How to get item.docId so that i can get url for pdf in firestore

i'm trying to implement pdf viewer from url stored in firestore in react js
how i can get item.docId in setPdfUrls please help me out i'm new to react js and web development
Where I'm stuck is that I don't understand how to do it please help
How to get item.docId so that i can get url for pdf in firestore
`
import React, { useState, useEffect, useContext } from "react";
import { Card, Header, Player } from "../components";
import * as ROUTES from "../constants/routes";
import { FirebaseContext } from "../context/firebase";
import { ref, getDownloadURL } from "firebase/storage";
import { storage } from "../lib/firebase.prod";
import { SelectProfileContainer } from "./profiles";
import { FooterContainer } from "./footer";
export function BrowseContainer({ slides }) {
var [pdfUrls, setPdfUrls] = useState([]);
const [resume, setResume]=useState(null);
useEffect(()=>{
getDownloadURL(ref(storage, 'Resume.pdf')).then((url)=>{
setResume(url);
})
},[]);
const [category, setCategory] = useState("articles");
const [profile, setProfile] = useState({});
const [loading, setLoading] = useState(true);
const [slideRows, setSlideRows] = useState([]);
const { firebase } = useContext(FirebaseContext);
const user = firebase.auth().currentUser || {};
useEffect(() => {
setTimeout(() => {
setLoading(false);
}, 3000);
}, [profile.displayName]);
useEffect(() => {
setSlideRows(slides[category]);
}, [slides, category]);
return profile.displayName ? (
<>
<Card.Group>
{slideRows.map((slideItem) => (
<Card key={`${category}-${slideItem.title.toLowerCase()}`}>
<Card.Title>{slideItem.title}</Card.Title>
<Card.Entities>
{slideItem.data.map((item) => (
<Card.Item key={item.docId} item={item}>
<Card.Meta>
<Card.SubTitle>{item.title}</Card.SubTitle>
<br/>
<br/>
</Card.Meta>
<Card.Image
src={item.image} alt={item.title}/>
</Card.Item>
))}
</Card.Entities>
<Card.Feature category={category}>
<Player>
<Player.Button />
<Player.Video src={resume} />
</Player>
</Card.Feature>
</Card>
))}
</Card.Group>
<FooterContainer />
</>
) : (
<SelectProfileContainer user={user} setProfile={setProfile} />
);
}
`

Firebase reading data two times from firestore

I am trying to read the data from a Firebase Firestore collection called 'posts'. Its having few documents in it. When I am using the following code to read data, I am able to read it but two times:
code in posts.jsx file:
import React, { useEffect, useState } from "react";
import '../index.css';
import '../../node_modules/antd/dist/antd.min.css';
import PostSnippet from './PostSnippet';
import _ from 'lodash';
import { PageHeader } from "antd";
import { db } from '../firebase.js';
import { collection, getDocs } from "firebase/firestore";
function Posts(props) {
const [posts, setPosts] = useState([]);
useEffect(() => {
const fetchData = async () => {
const postRef = collection(db, 'posts');
const postSnap = await getDocs(postRef);
postSnap.forEach(doc => {
let data = doc.data()
let { id } = doc
let payload = {
id,
...data,
}
setPosts((posts) => [...posts, payload])
})
}
fetchData()
.catch(console.error);
}, [])
return (
<div className="posts_container">
<div className="page_header_container">
<PageHeader
style={{
border: '5px solid rgb(235, 237, 240)',
fontSize: '25px',
margin: '40px',
}}
title="Post"
/>
</div>
<div className="articles_container">
{
_.map(posts, (article, idx) => {
return (
<PostSnippet
key={idx}
id={article.id}
title={article.title}
content={article.content.substring(0, 300)} />
)
})
}
</div>
</div>
)
}
export default Posts;
Code in PostSnippet.jsx file which is used to give the view to individual cards:
import React from "react";
import { Card } from "antd";
import { Link } from "react-router-dom";
const PostSnippet = (props) => {
return (
<>
<div className="post_snippet_container" style={{ margin: "40px" }}>
<Card
type="inner"
title={props.title}
extra={
<Link to={`/post/${props.id}`}>
Refer the Article
</Link>}
>
<p className="article_content">
{
props.content.split('\n').map((paragraph, idx) => {
return <p key={idx}>{paragraph}</p>
})
}
</p>
</Card>
</div>
</>
)
}
export default PostSnippet;
Actual data in Firestore:
Retried data from the firestore:
setPosts((posts) => [...posts, payload])
You only ever add to the array, so when data is fetched for the second time, you grow your array to twice the size. Instead, replace the array with the new data. That way the second fetch will overwrite the first:
const fetchData = async () => {
const postRef = collection(db, 'posts');
const postSnap = await getDocs(postRef);
const newPosts = postSnap.docs.map(doc => {
return {
id: doc.id,
...doc.data(),
}
});
setPosts(newPosts);
}

react firebase firestore empty useEffect useState

having an issue, when the when nav to the comp the items state is empty, if I edit the code and page refreshes its shows up and if I add the state to the useEffect "[itemCollectionRef, items]" it's an inf loop but the data is their anyone have a better idea or way to fetch the data for display from firestore.
import React, { useState, useEffect } from "react";
import { Grid, Box, Button, Space } from "#mantine/core";
import { ItemBadge } from "../../components/NFAItemBadge";
import { useNavigate } from "react-router-dom";
import { db, auth } from "../../firebase";
import { getFirestore, query, getDocs, collection, where, addDoc } from "firebase/firestore";
import { useAuthState } from "react-firebase-hooks/auth";
const ItemTrack = () => {
const [user, loading, error] = useAuthState(auth);
const navigate = useNavigate();
const [items, setItems] = useState([]);
const itemCollectionRef = collection(db, "items");
useEffect(() => {
//if(!user) return navigate('/');
//if(loading) return;
const q = query(itemCollectionRef, where("uid", "==", user.uid));
const getItems = async () => {
const data = await getDocs(q);
setItems(data.docs.map((doc) => ({ ...doc.data(), id: doc.id })));
console.log("Fetched Items: ", items);
};
getItems();
}, []);
if (loading) {
return (
<div>
<p>Initialising User....</p>
</div>
);
}
if (error) {
return (
<div>
<p>Error: {error}</p>
</div>
);
}
if (user) {
return (
<Box sx={{ maxWidth: 1000 }} mx="auto">
</Box>
);
} else {
return navigate("/");
}
};
export default ItemTrack;
It will depend how you will render the data from the useEffect. setState does not make changes directly to the state object. It just creates queues for React core to update the state object of a React component. If you add the state to the useEffect, it compares the two objects, and since they have a different reference, it once again fetches the items and sets the new items object to the state. The state updates then triggers a re-render in the component. And on, and on, and on...
As I stated above, it will depend on how you want to show your data. If you just want to log your data into your console then you must use a temporary variable rather than using setState:
useEffect(() => {
const newItems = data.docs.map((doc) => ({ ...doc.data(), id: doc.id }))
console.log(newItems)
// setItems(newItems)
}, [])
You could also use multiple useEffect to get the updated state object:
useEffect(() => {
setItems(data.docs.map((doc) => ({ ...doc.data(), id: doc.id })))
}, [])
useEffect(() => { console.log(items) }, [items])
If you now want to render it to the component then you have to call the state in the component and map the data into it. Take a look at the sample code below:
useEffect(() => {
const q = query(itemCollectionRef, where("uid", "==", user.uid));
const getItems = async () => {
const data = await getDocs(q);
setItems(data.docs.map((doc) => ({ ...doc.data(), id: doc.id })));
};
getItems();
}, []);
return (
<div>
<p>SomeData: <p/>
{items.map((item) => (
<p key={item.id}>{item.fieldname}</p>
))}
</div>
);

Problem when maping array - React with Redux Toolkit

I have the following problem: I use a fatch API to get all the products I have registered in my database (mongodb), then I store the result in a slice called products-slice which has an array as its initial state empty. Until then everything is in order. As I need information the time the homepage is loaded, I use the useEffect hook to fetch the products I have registered. Then I pass this array as props to a component, and make a map. The problem is that when the component loads, the information is not local.
código do backend
module.exports.fetchProduct = async (req, res) => {
try {
const products = await Product.find({});
if (products) {
res.json(products);
}
} catch (error) {
console.log(error);
}
};
productsActions.js
export const fetchProducts = () => {
return async (dispatch) => {
try {
const response = await fetch("http://localhost:xxxx/xxxxxx");
const data = await response.json();
let loadedProducts = [];
for (const key in data) {
loadedProducts.push({
id: data[key]._id,
productName: data[key].productName,
price: data[key].price,
imageUrl: data[key].imageUrl,
});
}
dispatch(setProducts(loadedProducts));
} catch (error) {
console.log(error);
}
};
};
home.jsx
import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Container } from "react-bootstrap";
import {fetchProducts} from '../../store/actions/productsActions';
import Hero from "../hero/Hero";
import Footer from "../footer/Footer";
import DisplayProductsList from "../displayProduct/DisplayProductsList";
export default function Home() {
const productsInfo = useSelector((state) => state.products.products);
console.log(productsInfo);
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchProducts());
}, [dispatch]);
return (
<>
<Hero />
<DisplayProductsList products={productsInfo} />
<Container fluid>
<Footer></Footer>
</Container>
</>
);
}
product-slice.js
const initialState = {
products: [],
};
const productSlice = createSlice({
name: "product",
initialState,
reducers: {
setProducts(state, action) {
state.products.push(action.payload);
},
},
});
export const { setProducts } = productSlice.actions;
export default productSlice.reducer;
component where I'm mapping
export default function DisplayProductsList(props) {
console.log(props);
return (
props.products.map((product) => (
<DisplayProducts
key={product.id}
imageUrl={product.imageUrl}
name={product.productName}
price={product.price}
/>
))
);
}
console.log output in the above component
enter image description here

How can i passing id which match?

I'm new to ReactJS, please don't judge me.
So I fetch some user and I want to display them one by one, but as you can see in this picture I don't get the ID, but I get the id in the iteration
import React, { useState, useEffect } from 'react';
import '../App.css';
import { Link } from 'react-router-dom';
function Users() {
useEffect(() => {
fetchItems();
}, []);
const [items, setItems] = useState([]);
const fetchItems = async () => {
const data = await fetch('https://jsonplaceholder.typicode.com/users');
const items = await data.json();
console.log(items.id);
setItems(items);
};
return (
<div>
{items.map(item => (
<h1 key={item.id}>
<Link to={`/users/${item.id}`}>{item.name}</Link>
</h1>
))}
</div>
);
}
export default Users;
and here is my UserDetails :
import React, { useState, useEffect } from 'react';
import '../App.css';
function UserDetail({ match }) {
useEffect(() => {
fetchItem();
console.log(match.id);
}, [match]);
const [user, userItem] = useState({});
const fetchItem = async () => {
const data = await fetch(
`https://jsonplaceholder.typicode.com/users/${match.id}`
);
const user = await data.json();
console.log(user);
};
return (
<div>
<h1>Item</h1>
</div>
);
}
export default UserDetail;
and i get this error.
I dont' get my id,and i don't know why.

Categories

Resources