This is my first time I am asking question here. If I make any mistake, sorry from now on. I've been trying to build infinite scroll bar with 3 columns. But when the next data is fetched, the images act really weird. I've tried almost everything like "fixed, flex-nowrap", etc.. with tailwind. But none of them worked. I also made research almost for 3 hours and couldn't find any helpful resources. I'd be glad if you could help me!
video: https://streamable.com/ouk16y
import React, { useState, useEffect } from "react";
import InfiniteScroll from "react-infinite-scroll-component";
//components
//icons
import { AiOutlineHeart, AiOutlinePlus } from "react-icons/ai";
//styling
const Gallery = () => {
const apiKey = "apiKey";
const [pictures, setPictures] = useState([]);
const [page, setPage] = useState(1);
//fetching the api data
useEffect(() => {
fetch(
`https://api.unsplash.com/search/photos?page=${page}&query=office&client_id=${apiKey}`
)
.then((resp) => {
return resp.json();
})
.then((data) => {
const pictureData = [...new Set(data.results)];
setPictures((prev) => [...prev, ...pictureData]);
});
}, [page]);
return (
<InfiniteScroll
dataLength={pictures.length}
next={() => setPage((prev) => prev + 1)}
hasMore={true}
scrollThreshold={0.3}
>
<div className="columns-1 lg:columns-3 col-auto lg:w-5/6 mx-auto gap-8 space-y-4">
{pictures.map((picture) => (
<div className="" key={picture.id}>
<div className="flex p-2 lg:hidden ">
<img
className="rounded-full w-10 h-10"
src={picture.user.profile_image.medium}
alt={`${picture.name} profile`}
/>
<span className="pt-2 pl-2">{picture.user.name}</span>
</div>
<img className="resize-none" src={picture.urls.regular} />
{/* //icons for small devices// */}
<div className="flex mt-2 pl-2 mb-8 lg:hidden">
<AiOutlineHeart className="w-8 h-8 text-gray-600" />
<AiOutlinePlus className="w-8 h-8 ml-2 text-gray-600 " />
<button className="w-40 border ml-auto mr-4">Download</button>
</div>
</div>
))}
</div>
</InfiniteScroll>
);
};
export default Gallery;
'''
Related
I am facing a hydration error when trying to add motion from framer-motion in any element from the file.
Without motion, everything works fine:
import { useRef, useState, useEffect } from 'react';
import { usePathname, useRouter } from 'next/navigation';
import Image from 'next/image';
import Link from 'next/link';
import { Icon, Dropdown, UserIcon } from '#ui';
import { menuItems } from '#utils/menu';
import useOutsideClick from '#hooks/useOutsideClick';
import { useAppDispatch, useAppSelector } from '#hooks/reduxHooks';
import { triggerCloseMenu } from 'redux/Slices/menuSlice';
import { motion } from 'framer-motion';
const Header = () => {
const [url, setUrl] = useState<string>('/images/logoLight.png');
const dispatch = useAppDispatch();
const close = () => {
dispatch(triggerCloseMenu());
};
const menuOpen = useAppSelector((state) => state.menu.menuOpen);
const wrapperRef = useRef(null);
const pathname = usePathname();
const router = useRouter();
useOutsideClick(wrapperRef, close);
useEffect(() => {
setUrl(
pathname === '/'
? !menuOpen
? '/images/logoLight.png'
: '/images/logoDark.png'
: '/images/logoDark.png',
);
}, [menuOpen, pathname]);
return (
<header
className="fixed top-0 z-50 w-screen bg-transparent "
ref={wrapperRef}
>
<nav className=" mx-auto flex w-full max-w-[2000px] items-center justify-between py-9 px-7 ">
<div className="flex items-center justify-center space-x-6">
<Icon />
<Image
src={url}
alt="logo_image"
width={120}
height={0}
className="mb-1"
onClick={() => {
router.push('/');
close();
}}
/>
</div>
<div className="relative flex items-center space-x-10">
<div className="hidden space-x-14 lg:flex">
{menuItems.map((i: Menu) => (
<Link
href={i.path}
key={i.id}
className={`${
pathname !== i.path ? 'font-normal' : 'font-extrabold'
}
text-lg text-white transition duration-300 ease-linear`}
>
{i.label}
</Link>
))}
</div>
<UserIcon />
</div>
</nav>
<Dropdown />
</header>
);
};
export default Header;
But if I replace with <motion.header> </motion.header> I am getting this error : Error: Hydration failed because the initial UI does not match what was rendered on the server.
I am using latest version of Nextjs (without app directory), and framer-motion v8
in checkOut js im unable to access the data inside the items arrey but i can access the length how is it possible i added 3 items i can see the items.lenth but when try to use items.map its not working showing error:
TypeError: Cannot read properties of undefined (reading 'image')
store.ts
import { configureStore } from "#reduxjs/toolkit";
import basketReducer from "./basketSlice";
//this is redux like a global store to store users items data
//when users put the items in the shopping cart
export const store = configureStore({
reducer: {
basket: basketReducer,
},
});
busketSlice.ts
import { createSlice } from "#reduxjs/toolkit";
interface BasketItem {
id: string;
title: string;
image: string;
description: string;
price: number;
category: string;
}
const initialState = {
items: [] as BasketItem[],
};
export const basketSlice = createSlice({
name: "basket",
initialState,
reducers: {
addToBasket: (state, action) => {
state.items = state.items.concat(action.payload);
},
removeFromBasket: (state, action) => {
const index = state.items.findIndex((basketItem: any) => basketItem.id === action.payload.id)
let newBasket = [...state.items];
if (index >= 0){
//if item exists in the basket remove it ...
newBasket.splice(index, 1);
} else {
console.warn(`cant remove (id: ${action.payload.id}) because its not in busket`)
}
state.items = newBasket;
},
},
});
export const { addToBasket, removeFromBasket } = basketSlice.actions;
// Selectors - This is how we pull information from the Global store slice
export const selectItems = (state: any) => state.basket.items;
export const selectTotal = (state: any) => state.busket.items.reduce((total:any, item:any) => total + item.price, 0);
const basketReducer = basketSlice.reducer;
export default basketReducer;
Cards.tsx
import Image from 'next/image';
import React, { useEffect, useState } from 'react';
import { StarIcon } from '#heroicons/react/solid';
// import Currency from 'react-currency-formatter';
import { useDispatch } from 'react-redux';
import { addToBasket } from "../basketSlice"
export default function Cards({id,title,image,description,price,category}: any) {
const dispatch = useDispatch()
const addItemsToBusket = () => {
const product = {
id,title,image,description,price,category
}
dispatch(addToBasket(product))//sending the product as an action to the redux store
}
const [rating, set] = useState(5);
const [hasPrime, setH] = useState(Math.random() < 1)
useEffect(() => {
set(Math.floor(Math.random() * 5) + 1 );
}, [])
useEffect(() => {
setH(Math.random() < 0.5 );
}, [])
return (
<div className="relative z-30 flex flex-col p-10 m-5 bg-white ">
<p className='absolute text-xs italic right-2 top-2'>{category}</p>
<Image className='mx-auto' src={image} height={200} width={200} alt=""/>
<h4 className='my-3'>{title}</h4>
<div className='flex'>
{Array(rating).fill(rating).map((_, i) => (
<StarIcon key={i} className='h-6 text-yellow-500'/>
))}
</div>
<p className='my-2 text-xs line-clamp-2 '>{description}</p>
<div>
{/* <Currency quantity={props.price} currency="INR"/> */}
<p className='mb-5'>₹{price}</p>
</div>
{hasPrime && (
<div className='flex items-center -mt-5 space-x-2'>
<img
className='w-12'
src="https://links.papareact.com/fdw" alt="" />
<p className='text-xs text-gray-500'>Free Next-Day Delivary</p>
</div>
)}
<button onClick={addItemsToBusket} className='mt-auto button'>Add to Busket</button>
</div>
)
}
ProductsFeed.tsx
import React from 'react'
import Cards from './Cards'
export default function({ products }: any) {
return (
<div className="grid grid-flow-row-dense mx-auto md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 md:-mt-40 lg:-mt-52">
{products.slice(0,4).map((product: any) => (
<Cards
key={product.id}
id={product.id}
title={product.title}
price={product.price * 60}
description={product.description}
category={product.category}
image={product.image}
/>
))}
<img className="md:col-span-full" src="https://links.papareact.com/dyz" alt="" />
<div className='md:col-span-2'>
{products.slice(4,5).map((product: any) => (
<Cards
key={product.id}
id={product.id}
title={product.title}
price={product.price * 60}
description={product.description}
category={product.category}
image={product.image}
/>
))}
</div>
{products.slice(5, products.length).map((product: any) => (
<Cards
key={product.id}
id={product.id}
title={product.title}
price={product.price * 60}
description={product.description}
category={product.category}
image={product.image}
/>
))}
</div>
)
}
checkout.tsx
import React from 'react'
import Nav from '../components/Nav'
import { signIn, signOut, useSession } from "next-auth/react"
import { useSelector } from 'react-redux';
import { selectItems } from '../basketSlice';
import CheckOutProduct from '../components/CheckOutProduct';
export default function CheckOut() {
const { data: session } = useSession()
const items = useSelector(selectItems);
console.warn(items)
return (
<div className='h-screen bg-gray-100'>
<Nav />
<main>
{!session? (
<div>
<div className='flex items-center justify-start p-10 m-10 space-x-4 overflow-hidden bg-white md:space-x-10'>
<img src="/checkout.svg" className='h-[7rem] w-[7rem] sm:w-[15rem] sm:h-[15rem]' alt=""/>
<div className=''>
<h1 className='font-bold md:text-[2rem] mb-1'>Your Amazon Cart is empty</h1>
<p className='text-[#007185] hover:text-red-600 cursor-pointer hover:underline hover'>Shop today's deals</p>
<button
className='px-10 py-2 mt-4 button'
onClick={() => signIn()}>Sign in to your account</button>
</div>
</div>
<div className=' h-[5rem] bg-white mx-10' />
</div>
): (
<div>
<div className='flex items-center justify-start p-10 m-10 space-x-4 overflow-hidden bg-white md:space-x-10'>
<img src="/checkout.svg" className='h-[7rem] w-[7rem] sm:w-[15rem] sm:h-[15rem]' alt=""/>
<div className=''>
<h1 className='font-bold md:text-[2rem] mb-1'>
{items.length === 0? "Your Amazon Cart is empty": "Shoping Basket"}
</h1>
<p className='text-[#007185] hover:text-red-600 cursor-pointer hover:underline hover'>Shop today's deals</p>
</div>
</div>
<div className='mx-10 bg-white '>
{items.length !== 0 && `You have ${items.length} items in your busket.`}
{items.map(({item, i}: any) => {
<CheckOutProduct
key={i}
image={item.image}
price={item.price}/>
})}
</div>
</div>
)}
</main>
</div>
)
}
checkOutProduct.tsx
import Image from 'next/image'
import React from 'react'
export default function CheckOutProduct({ id,title,image,description,price,category }: any) {
return (
<div className='grid grid-cols-5'>
<Image src={image} height={200} width={200} alt=""/>
<p>{price}</p>
</div>
)
}
Try to add like below because concat will not change object reference since updated values will not show in component.
addToBasket: (state, action) => {
state.items = [...state.items, ...action.payload];
}
Sticker.ts
import React from "react";
import Image from "next/image";
import {GetServerSideProps, InferGetServerSidePropsType } from 'next';
import Product from "models/Product";
import currencyFormatter from "lib/currencyFormatter";
import mongoose from "mongoose";
import handler from "pages/api/pincode";
// const Sticker = (props: any) => {
const Sticker = ({products}) => {
// const products = JSON.parse((props?.products));
console.log("list of product "+ products)
return (
<div>
<section className="text-gray-600 body-font">
<div className="container px-5 py-24 mx-auto">
<div className="flex flex-wrap -m-4 justify-centr">
{/* {products?.map((dt: any, idx: number) => */}
{/* <div className="lg:w-1/4 md:w-1/2 p-4 w-full" key={idx}> */}
<div className="lg:w-1/4 md:w-1/2 p-4 w-full" >
{/* <a href={`./product/${dt?.category}/${dt?.id}`} className="block relative h-68 rounded overflow-hidden"> */}
<a href="./product/{category}/slug[jhbjh]" className="block relative h-68 rounded overflow-hidden">
<Image
alt="ecommerce"
className="object-cover cursor-pointer object-center w-full h-full block"
src="https://m.media-amazon.com/images/I/61SFAM62ucL._SL1280_.jpg"
width="100"
height="100"
/>
</a>
<div className="mt-4">
<h3 className="text-gray-500 text-xs tracking-widest title-font mb-1">
Home Decor
</h3>
<h2 className="text-gray-900 title-font text-lg font-medium">
Paper Plane Design Quote and Motivational Posters 12X18
</h2>
<p className="mt-1">{currencyFormatter(179)}</p>
</div>
</div>
{/* )} */}
</div>
</div>
</section>
</div>
);
};
export async function getServerSideProps(context) {
if(!mongoose.connections[0].readyState){
await mongoose.connect(process.env.MONGO_URI)
}
let products = await Product.find()
return {
// props: { products },
props: { products : JSON.parse(JSON.stringify(products)) },
}
}
export default Sticker;
_app.tsx
import React, { useEffect, useState } from 'react'
import { NextUIProvider, useSSR } from '#nextui-org/react';
import '../styles/globals.css'
import Navbar from '../modules/body/Navbar';
import Footer from '../modules/body/Footer';
import theme from "../themes";
import { AppProps } from 'next/app';
// import SideNavbar from '../mainComponent/SideNavbar'
function MyApp({ Component, pageProps }: AppProps) {
const [cart, setCart] = useState<object>({})
const [subTotal, setSubTotal] = useState<number>(0)
const { isBrowser } = useSSR();
useEffect(() => {
try {
if (localStorage.getItem("cart")) {
setCart(JSON.parse(localStorage.getItem("cart") || ""))
saveCart(JSON.parse(localStorage.getItem("cart") || ""))
}
} catch (error) {
console.log(error);
localStorage.clear()
}
}, [])
const saveCart = (myCart: object) => {
localStorage.setItem("cart", JSON.stringify(myCart))
// let keys = Object.keys(myCart);
const subt = Object.values(myCart).reduce((acc, curr) => acc + curr?.price * curr?.qty,0);
setSubTotal(subt)
}
const addToCart = (itemCode, qty, price, name, size, variant) => {
let newCart = cart;
if (itemCode in cart) {
newCart[itemCode].qty = cart[itemCode].qty + qty
}
else {
newCart[itemCode] = { qty: 1, price, name, size, variant }
}
setCart(newCart)
saveCart(newCart)
}
const removeFromCart = (itemCode, qty, price, name, size, variant) => {
let newCart = JSON.parse(JSON.stringify(cart));
if (itemCode in cart) {
newCart[itemCode].qty = cart[itemCode].qty - qty
}
if (newCart[itemCode]["qty"] <= 0) {
delete newCart[itemCode]
}
setCart(newCart)
saveCart(newCart)
}
const clearCart = () => {
setCart({})
saveCart({})
}
return isBrowser && (
<NextUIProvider theme={theme}>
<Navbar key={subTotal} cart={cart} addToCart={addToCart} removeFromCart={removeFromCart}
clearCart={clearCart} subTotal={subTotal} />
{/* <SideNavbar /> */}
<Component cart={cart} addToCart={addToCart} removeFromCart={removeFromCart}
clearCart={clearCart} subTotal={subTotal} {...pageProps} />
<Footer />
</NextUIProvider>
)
}
export default MyApp
I tried every method posted on the browser but still it shows undefined. If you help me to find out the solution of this problem then i will be very happy and feel blessed with this coding environment. please solve this as soon as possible. My whole project is stucked because of this error.
I'm using tailwind with react. The problem is that my paragraph text is quite long. I have applied overflow-hidden to the div. But it is still flowing outside div. But it is not visible. But it is ruining my UI. As the pic is also getting stretched out due to the text overflowing. How do I stop the text from overflowing. So I only get the text that is visible inside div. I am using subString(0,50). It will fix the issue, if I use a smaller number. But I want to know is there any other way to fix it. So that the text does not go outside the div and occupies full space of div only. I tried many other properties to fix this issue. But no success so far.
I have uploaded a gif of my problem on imgur
Code
import React, { useEffect, useState } from "react";
import { BsBoxArrowUpRight, BsPencilSquare, BsTrash } from "react-icons/bs";
import { getActors } from "../api/actor";
let currentPageNo = 0;
let limit = 20;
export default function Actors() {
const [actors, setActors] = useState([]);
const [reachedToEnd, setReachedToEnd] = useState(false);
const fetchActors = async (pageNo) => {
const { profiles, error } = await getActors(pageNo, limit);
if (!profiles.length) {
currentPageNo = pageNo - 1;
return setReachedToEnd(true);
}
setActors([...profiles]);
};
const handleOnNextClick = () => {
if (reachedToEnd) return;
currentPageNo += 1;
fetchActors(currentPageNo);
};
const handleOnPrevClick = () => {
if (currentPageNo <= 0) return;
currentPageNo -= 1;
fetchActors(currentPageNo);
};
useEffect(() => {
fetchActors(currentPageNo);
}, []);
return (
<div className="p-5">
<div className="grid grid-cols-4 gap-5">
{actors.map((actor) => {
return <ActorProfile profile={actor} key={actor.id} />;
})}
</div>
<div className="flex justify-end items-center space-x-3 mt-5">
<button
type="button"
className="text-primary dark:text-white hover:underline"
onClick={handleOnPrevClick}
>
Prev
</button>
<button
type="button"
className="text-primary dark:text-white hover:underline"
onClick={handleOnNextClick}
>
Next
</button>
</div>
</div>
);
}
const ActorProfile = ({ profile }) => {
if (!profile) return null;
const [showOptions, setShowOptions] = useState(false);
const handleOnMouseEnter = () => {
setShowOptions(true);
};
const handleOnMouseLeave = () => {
setShowOptions(false);
};
let acceptedNameLength = 15;
const getName = (name) => {
if (name.length <= acceptedNameLength) return name;
return name.substring(0, acceptedNameLength) + "...";
};
const { name, avatar, about = "" } = profile;
return (
<div className="bg-white dark:bg-secondary shadow dark:shadow rounded h-20 overflow-hidden">
<div
onMouseEnter={handleOnMouseEnter}
onMouseLeave={handleOnMouseLeave}
className="flex cursor-pointer relative"
>
<img
src={avatar}
alt={name}
className="w-20 aspect-square object-cover"
/>
<div className="px-2 flex-1">
<h1 className="text-xl text-primary dark:text-white whitespace-nowrap">
{getName(name)}
</h1>
<p className="text-primary dark:text-white opacity-75">
{about.substring(0, 30)}
</p>
</div>
<Options visible={showOptions} />
</div>
</div>
);
};
const Options = ({ visible, onEditClick, onDeleteClick }) => {
if (!visible) return null;
return (
<div className="absolute inset-0 bg-primary bg-opacity-25 backdrop-blur-sm flex justify-center items-center space-x-5">
{" "}
<button
onClick={onDeleteClick}
type="button"
className="text-primary bg-white p-2 rounded-full hover:opacity-80 transition"
>
<BsTrash />
</button>
<button
onClick={onEditClick}
type="button"
className="text-primary p-2 rounded-full bg-white hover:opacity-80 transition"
>
<BsPencilSquare />
</button>
</div>
);
};
I want to add card using react-bootstrap in a project. I used Grid and CardDeck option from react-bootstrap. But all cards comes in a column (like this). But I want this cards comes with side by side, not in row.(I want my output like this image).
Here the code for card section
import Card from 'react-bootstrap/Card';
const Course = (props) => {
const {title, price,details,img} = props;
return (
<div>
<div className="col-md-4 col-12 mt-5 mx-auto">
<Card>
<Card.Img variant="top" src={img} />
<Card.Body>
<Card.Title>{title}</Card.Title>
<Card.Title>{price}</Card.Title>
<Card.Text>
{
details
}
</Card.Text>
</Card.Body>
</Card>
</div>
</div>
);
};
export default Course;
Where I pass the value
import React from "react";
import fakeData from "../FakedData/FakeData";
import Course from "../Course/Course";
import CardDeck from 'react-bootstrap/CardDeck';
const Home = () => {
return (
<div>
<div className="container">
<div className="row">
<CardDeck>
{fakeData.map((data) => {
return (
<Course
key={data.id}
title={data.title}
price={data.price}
details={data.details}
img={data.img}
/>
);
})}
</CardDeck>
</div>
</div>
</div>
);
};
export default Home;
I don't try this, it's the old way with modulo, should work, but not responsive
const Home = () => {
const numInRow = 4;
return (
<div>
<div className="container">
<div class="d-flex justify-content-center"> // <---- div first row
{fakeData.map((data, idx) => { //<--- note the idx
return (
<Course
key={data.id}
title={data.title}
price={data.price}
details={data.details}
img={data.img}
/>
{idx % numInRow === 0 && </div><div class="d-flex justify-content-center">} // <--- use modulo to close row and open a new one
);
})}
</div> //<-- div last row
</div>
</div>
);
};