Pagination with Firebase v9 and React not working - reactjs

I'm trying to build a page that paginates all the data from a collection, however I can't seem to figure out how to do it and I haven't found anyone who's done it either.
I've tried to get the documentList.length, but that also isn't working.
function Sessions() {
const location= useLocation();
const user= location.state.user;
const [sesList, setSesList] = useState([]);
const subRef=collection(db, 'Users',user,'Sessions');
let q = query(subRef,orderBy('time','desc'),limit(5));
const DocumentSnapshot=getDocs(q);
const last= DocumentSnapshot[DocumentSnapshot.length-1]
const next=()=>{
return q=query(subRef,orderBy('time','desc'), startAfter(last), limit(5))
}
const prev=(first)=>{
return q=query(subRef, orderBy('time','desc'), endBefore(first['time','desc']), limitToLast(5))
}
useEffect(() => { //loads all the tenants
onSnapshot(q, (snapshot) => {
setSesList(
snapshot.docs.map((doc) => ({ ...doc.data(), id: doc.id }))
);
});
}, []);
return (
<div className='Sessions'>
<Sidebar className='nav'
L1={<Link to='/Dashboard' state={{user:user}}>Dashboard</Link>}
L2={<Link to='/Sessions' state={{user:user}}>Sessions</Link>}/>
<div className="bod">
<div className="startCard1">
<h1>Sessions</h1>
</div>
<div className="Recent">
<h1>Your Sessions:</h1>
<div className="recSes">
{sesList.map((REC)=>{
return(
<div className="rowCard">
<div className="rowCardTitle">
<h3> Subject: {REC.subject}</h3>
</div>
<div className="WTime">
<h3>Work Minutes: {REC.WorkTime}</h3>
</div>
<div className="BTime">
<h3> Break Minutes: {REC.BreakTime}</h3>
</div>
<div className="Atime">
<h3>Date: {REC.time}</h3>
</div>
</div>
)
})}
</div>
</div>
<div className="buttoninlin">
<button className='Gobtn1'>Previous </button>
<button className='Gobtn1' onClick={next}>Next</button>
</div>
</div>
</div>
)
}
export default Sessions
expected result: next button shows next documents, back button shows previous documents

Related

Adding items to cart in react js

In reactjs, what code would I have to write in my two components(homepage.js with an add-to-cart button and a checkout page with a clear cart button? This is my Homepage.js where I fetch the items from my backend server, map, and display them on the page.
function Home() {
const [data, setData] = useState([]);
useEffect(() => {
// auto-login
fetch("/coffees").then((res) => {
if (res.ok) {
res.json().then((data) => setData(data))
}
});
}, [])
console.log(data)
return (
<>
<div className="box">
<div className="projo">
<h2 >Welcome to Coffee-cafe</h2>
</div>
<div className="projects">
{data.map((data) =>{
return(
<div className="card">
<img className="avatar" src={data.coffee_image} alt="coffee"></img>
<div className="card-content">
<h4><b>{data.coffee_name}</b></h4>
<p id="desc">{data.description}</p>
<p className="price">{data.price}</p>
{/* <p>{data.category}</p> */}
<button onClick={() => ({})} className="btn1" id="btn1">Add to Cart</button>
</div>
</div>
)
})}
</div>
</div>
</>
)
}
export default Home;
For the Checkout.js, this is what I have currently.
function Checkout() {
return (
<>
<div className="section">
<div className="photo">
<img className="dp" src={image1} alt="coffee"></img>
<div className="info">
<h3>Coffee:</h3>
<p>Price:</p>
<p>Category:</p>
<div className="check-out-btn">
{/* <button className="add">AddToCart</button> */}
<button className="delete">ClearCart</button>
</div>
</div>
</div>
</div>
take a look for a global states like redux , context,or zustand
for my recommendation, I suggest zustand is less code than context and redux and short learning curve
carts =[]
setItemToCart(item){
const isExist = carts.find(c => c.id ===item.id)
if(isExit){
const qty = isExit.qty+item.qty
const newItem= {...item,qty}
// push is not recommended to use because it mutates state
carts.push(newItem)
}else{
carts.push(item)
}
}

Mapping through a object that is the only object in an array of list (nested object)

Im having a hard time mapping through an object in an array. So i have this code and im able to display the array but the comments (object) is not showing. that is im not able to access my nested object. I have scouted the internet and all the solutions there havent helped me. Any ideas or push to the right direction is greatly appreciated
function SingleTweet() {
const [count, setCount] = useState(0)
const [single, setSingle] = useState({})
const { id } = useParams()
useEffect(() => { axios.get(`https://localhost:44368/api/users/${id}`).then((res) => {
console.log(res.data, "list of heroes ");
setSingle(res.data);
});
}, []);
const [coms, setCom] = useState({})
useEffect(() => { axios.get(`https://localhost:44368/api/comments/${id}`).then((res) => {
console.log(res.data, "list of Comments ");
setCom(res.data);
});
}, []);
return (
<div className="app">
<LeftSidebar />
<div>
<div>
<h2>Home</h2>
</div>
<div className="post-1">
<div>
<Avatar src={single.profilePicture} />
</div>
<div>
<div>
<div>
<h3>
{single.name}
<div>
#{single.userName}
</div>
</h3>
</div>
<div className="post_headerDesription-1">
<p>{single.post}</p>
</div>
</div>
<img src={single.image} alt="" />
<div className="p_footer">
<Tweet />
<RepeatIcon />
<FavoriteBorderIcon />
<PublishOutlinedIcon />
</div>
</div>
</div>
{/* i want to display the comments here that belong to the post */}
</div>
<RightSidebar />
</div>
)
}
this is my console log of the api call
comments: (2) [{…}, {…}]
id: 1
image: "https://media2.giphy.com/media/Q2tS8xloz0cg0/giphy.gif"
name: "Robin"
post: "Batman said i couldnt go out tonight :("
profilePicture: "https://variety.com/wp-content/uploads/2021/08/Robin.jpg?w=681&h=383&crop=1"
userName: "robin"

Use State not updating as expected

Fairly new to react and trying to build a clone of The Movie Database site. I want this toggle switch to change my api call from movies to tv. It starts working after a couple clicks, but then it throws everything off and it's not displaying the correct items anyway. Not really sure what's going on here...or even why it starts working after two clicks. Anyone know whats up with this?
import React, { useState, useEffect } from "react";
import axios from "axios";
import API_KEY from "../../config";
const Popular = ({ imageUri }) => {
// GET POPULAR MOVIES
const [popularMovies, setPopularMovies] = useState("");
const [genre, setGenre] = useState("movie");
console.log(genre);
const getPopular = async () => {
const response = await axios.get(
`https://api.themoviedb.org/3/discover/${genre}?sort_by=popularity.desc&api_key=${API_KEY}`
);
setPopularMovies(response.data.results);
};
useEffect(() => {
getPopular();
}, []);
const listOptions = document.querySelectorAll(".switch--option");
const background = document.querySelector(".background");
const changeOption = (el) => {
let getGenre = el.target.dataset.genre;
setGenre(getGenre);
getPopular();
listOptions.forEach((option) => {
option.classList.remove("selected");
});
el = el.target.parentElement.parentElement;
let getStartingLeft = Math.floor(
listOptions[0].getBoundingClientRect().left
);
let getLeft = Math.floor(el.getBoundingClientRect().left);
let getWidth = Math.floor(el.getBoundingClientRect().width);
let leftPos = getLeft - getStartingLeft;
background.setAttribute(
"style",
`left: ${leftPos}px; width: ${getWidth}px`
);
el.classList.add("selected");
};
return (
<section className="container movie-list">
<div className="flex">
<div className="movie-list__header">
<h3>What's Popular</h3>
</div>
<div className="switch flex">
<div className="switch--option selected">
<h3>
<a
data-genre="movie"
onClick={(e) => changeOption(e)}
className="switch--anchor"
>
In Theaters
</a>
</h3>
<div className="background"></div>
</div>
<div className="switch--option">
<h3>
<a
data-genre="tv"
onClick={(e) => changeOption(e)}
className="switch--anchor"
>
On TV
</a>
</h3>
</div>
</div>
</div>
<div className="scroller">
<div className="flex flex--justify-center">
<div className="flex flex--nowrap container u-overScroll">
{popularMovies &&
popularMovies.map((movie, idX) => (
<div key={idX} className="card">
<div className="image">
<img src={imageUri + "w500" + movie.poster_path} />
</div>
<p>{movie.title}</p>
</div>
))}
</div>
</div>
</div>
</section>
);
};
export default Popular;
You're using the array index as your key prop when you're mapping your array.
You should use an id that is specific to the data that you're rendering.
React uses the key prop to know which items have changed since the last render.
In your case you should use the movie id in your key prop instead of the array index.
popularMovies.map((movie) => (
<div key={movie.id} className="card">
<div className="image">
<img src={imageUri + 'w500' + movie.poster_path} />
</div>
<p>{movie.title}</p>
</div>
));
Also
You're calling the api directly after setGenre. However state changes aren't immediate. So when you're making your api call you're still sending the last movie genre.
Two ways of fixing this:
You could call your function with the genre directly, and change your function so it handles this case:
getPopular('movie');
Or you could not call the function at all and add genre as a dependency of your useEffect. That way the useEffect will run each time the genre change.
useEffect(() => {
getPopular();
}, [genre]);
PS: You should consider splitting your code into more component and not interacting with the DOM directly.
To give you an idea of what it could look like, I refactored a bit, but more improvements could be made:
const Popular = ({ imageUri }) => {
const [popularMovies, setPopularMovies] = useState('');
const [genre, setGenre] = useState('movie');
const getPopular = async (movieGenre) => {
const response = await axios.get(
`https://api.themoviedb.org/3/discover/${movieGenre}?sort_by=popularity.desc&api_key=${API_KEY}`
);
setPopularMovies(response.data.results);
};
useEffect(() => {
getPopular();
}, [genre]);
const changeHandler = (el) => {
let getGenre = el.target.dataset.genre;
setGenre(getGenre);
};
const isMovieSelected = genre === 'movie';
const isTvSelected = genre === 'tv';
return (
<section className="container movie-list">
<div className="flex">
<MovieHeader>What's Popular</MovieHeader>
<div className="switch flex">
<Toggle onChange={changeHandler} selected={isMovieSelected}>
In Theaters
</Toggle>
<Toggle onChange={changeHandler} selected={isTvSelected}>
On TV
</Toggle>
</div>
</div>
<div className="scroller">
<div className="flex flex--justify-center">
<div className="flex flex--nowrap container u-overScroll">
{popularMovies.map((movie) => {
const { title, id, poster_path } = movie;
return (
<MovieItem
title={title}
imageUri={imageUri}
key={id}
poster_path={poster_path}
/>
);
})}
</div>
</div>
</div>
</section>
);
};
export default Popular;
const Toggle = (props) => {
const { children, onChange, selected } = props;
const className = selected ? 'switch--option selected' : 'switch--option';
return (
<div className={className}>
<h3>
<a
data-genre="movie"
onClick={onChange}
className="switch--anchor"
>
{children}
</a>
</h3>
<div className="background"></div>
</div>
);
};
const MovieHeader = (props) => {
const { children } = props;
return (
<div className="movie-list__header">
<h3>{children}</h3>
</div>
);
};
const MovieItem = (props) => {
const { title, imageUri, poster_path } = props;
return (
<div key={idX} className="card">
<div className="image">
<img src={imageUri + 'w500' + poster_path} />
</div>
<p>{title}</p>
</div>
);
};

Link same page with different parameters react using link

I want refresh page and send data using link but it don't work
I am using a link to send me to same page but with different parameters but it is not work and it is not refresh ... what I should do?
When I click the link it change from link but it is not change in the page and does not refresh with the data does not change. What should I do?
<Link to={`/NewDetails/${news[arr].id}`}> read more </Link>
the js I'm using is
const NewDetails = () => {
const { id } = useParams();
const [newsDetail, setNewsDetail] = useState("");
useEffect(() => {
async function fetchMyAPI() {
let news = await onGetNewsById(id);
setNewsDetail(news);
}
fetchMyAPI();
}, []);
const [news, setNews] = useState("");
useEffect(() => {
async function fetchMyAPI() {
let news = await onGetNews();
setNews(news);
}
fetchMyAPI();
}, []);
const last_num = news.length;
const last_3_num = news.length - 3;
return (
<div>
<div>
<NavBar />
</div>
<div className="row">
<div className="NewsDetails_Section">
<div className="text-center">
<div className="imageDetailsBackground">
<img className="ImageNewsDetails" src={Wallet} alt="bankimage" />
</div>
</div>
<div className="text-center" dir='rtl'>
<h1> {newsDetail.title} </h1>
</div>
<div className="Body_news_Details">
<p className="text-center"> {newsDetail.content} </p>
</div>
<div>
<div className="News_Details_" dir="rtl">
{Object.keys(news.slice(last_3_num, last_num), NewsImage.slice(last_3_num, last_num)).map(arr => (
<div className="NewSection_details" key={news[arr].id}>
<div className="ImageNews_Details">
<img className="ImageNews_Details" src={NewsImage[arr]} alt="bankimage" />
</div>
<div className="HeaderNews_Details">
<h4>{news[arr].title} </h4>
</div>
<div className="bodynews_details">
<p> {news[arr].content.slice(0, 100)}... </p>
</div>
<div className="ButtonNews_Details">
{/*
<Link Redirect push to={`/NewDetails/${news[arr].id}`}> */}
<Link to={`/NewDetails/${news[arr].id}`}> read more</Link>
</div>
</div>))}
</div>
</div>
</div>
</div>
</div>
);
}

Button Click to Render Div

I want to click the button and render its corresponding div. Should I add the the div's info that I want to render to the state?
I'm sure there's a few different ways to solve this but I want to do it the React way and maybe as a function component?
Updated
export default function About(props) (
const [isHidden, setIsHidden] = useState(true);
const handleClick = () => {
setIsHidden(!isHidden);
};
return (
<div className="row justify-content-md-center">
<div className="col-auto">
<CustomButton onClick={handleClick}>Website Develpment</CustomButton>
</div>
<div className="col-auto">
<CustomButton onClick={handleClick}>Wordpress Develpment</CustomButton>
</div>
<div className="col-auto">
<CustomButton onClick={handleClick}>Ecommerce Development</CustomButton>
</div>
</div>
<div className="row">
<div className="col-md-4">column 1</div>
<div className="col-md-4">column 2</div>
<div className="col-md-4">column 3</div>
</div>
);
)
You can store an ID as a string state variable, and set that variable on button press.
Then use ConditionalRendering to only display the div with the matching ID.
const {useState} = React;
function About(props) {
const [visibleItem, setVisibleItem] = useState('');
return (
<div>
<button onClick={() => setVisibleItem("website")}>
Show Website Develpment
</button>
<button onClick={() => setVisibleItem("wordpress")}>
Show Wordpress Develpment
</button>
<button onClick={() => setVisibleItem("ecommerce")}>
Show Ecommerce Development
</button>
{visibleItem === "website" &&
<div>
<h2>Wordpress Development</h2>
<p>Info about Wordpress and all the things I can do with it</p>
</div>
}
{visibleItem === "wordpress" &&
<div>
<h2>Ecommerce Development</h2>
<p>I can do eccomerce things too</p>
</div>
}
{visibleItem === "ecommerce" &&
<div>
<h2>Website Development</h2>
<p>Info about Webdev</p>
</div>
}
</div>
);
}
ReactDOM.render(
<About/>,
document.getElementById("react")
);
<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="react"></div>
If the sections were much bigger then I'd recommend splitting them out into separate components, or maybe doing an if or switch statement to select between them before the return, but the above snippet is a pattern I have used often with react.
You can create two states one holding array of button info to minimize repetition of code and another state to track the column clicked.
import React, { useState } from "react";
export default function About(props) {
const [colNum, setColNum] = useState('');
const [btnNames] = useState([
{
colId: 1,
name: "Website Develpment"
},
{
colId: 2,
name: "Wordpress Develpment"
},
{
colId: 3,
name: "Ecommerce Develpment"
}
]);
const handleClick = (id) => {
setColNum(id);
};
return (
<>
<div className="row justify-content-md-center">
{btnNames.map(element => (
<div className="col-auto" key={element.colId}>
<CustomButton onClick={()=> handleClick(element.colId)}>{element.name}</CustomButton>
</div>
))}
</div>
{colNum !== '' ? (<div className="row">
<div className="col-md-4">column {colNum}</div>
</div>) : null }
</>
);
}
So you can define showing value for each section in state, which initial should be false. Then we can handle this state with a function where built-in JS tools can be used (Object.entries, Object.fromEntries and map). The element will be displayed, the value of which will be true, and the rest will automatically become false. More details can be found here: https://codesandbox.io/s/happy-sea-nckmw?file=/src/App.js
import React, { useState } from "react";
import "./styles.css";
import styles from "./TestStyles.module.css";
import CustomButton from "./CustomButton";
export default function App() {
const [showDiv, setShowDiv] = useState({
web: false,
wordpress: false,
ecommerce: false
});
const showDivHandler = (val) => {
const newState = Object.fromEntries(
Object.entries(showDiv).map(([key, value]) => [key, (value = false)])
);
setShowDiv({
...newState,
[val]: !showDiv[val]
});
};
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<div className={styles.Section}>
<div className="col-auto">
<CustomButton clicked={() => showDivHandler("web")}>
Website Develpment
</CustomButton>
</div>
<div className="col-auto">
<CustomButton clicked={() => showDivHandler("wordpress")}>
Wordpress Develpment
</CustomButton>
</div>
<div className="col-auto">
<CustomButton clicked={() => showDivHandler("ecommerce")}>
Ecommerce Development
</CustomButton>
</div>
</div>
<div className={styles.Section} style={{marginTop: 20}}>
{showDiv.web && <div className={styles.Content}>column 1</div>}
{showDiv.wordpress && <div className={styles.Content}>column 2</div>}
{showDiv.ecommerce && <div className={styles.Content}>column 3</div>}
</div>
</div>
);
}
The custom button can look like this:
import React from "react";
const button = (props) => (
<button
onClick={props.clicked}
//some other props if need it(e.g. styles)
>
{props.children}
</button>
);
export default button;
This is how I solved it. Thanks for your help!
export default function About() {
const [visibleItem, setVisibleItem] = useState(1);
const [priceItems] = useState([
{
id: 1,
name: "website",
},
{
id: 2,
name: "wordpress",
},
{
id: 3,
name: "ecommerce",
},
]);
const handleClick = (id) => {
setVisibleItem(id);
};
return (
<div className="container-fluid pricing-wrapper">
<div className="row">
<div className="col">
<h1>Pricing</h1>
</div>
</div>
<div className="row">
<div className="col">
<p>Innovation that empowers your team while also reducing risk!</p>
<div className="seperator"></div>
</div>
</div>
<div className="row justify-content-md-center">
<div className="row justify-content-md-center">
{priceItems.map((item) => (
<div className="col-auto">
<CustomButton onClick={() => setVisibleItem(item.id)}>
{item.name}
</CustomButton>
</div>
))}
</div>
</div>
{priceItems
.filter((item) => item.id === visibleItem)
.map((item) => (
<PriceItem item={item} />
))}
</div>
);
}

Resources