Error 404 when trying to load lots of img - reactjs

I'm build a side project for fun using create-react-app, in said project I'm fetching urls for <imgs>(700+). When I render all the <img> I get a lot of 404 errors, I thought this happened because I was trying to load too many so I tried rendering only 50 on the initial load but I still get a lot of 404 errors, also sometimes images stutter. I checked all the links that gave me a 404 error and they seem ok so, what's happening here?
I plan to load 50 more when the user gets to the bottom of the page using useEffect.
const Card = ({name, title, imageURL, categories, leaderSkill, passive, links}) => {
return(
<>
<img src={imageURL} title={`${name} ${title}`} alt={`${name} ${title}`} loading="lazy"/>
</>
)
}
export default Card;
import Card from './Card';
import { useEffect, useState } from 'react';
const Cards = ({ data }) => {
const [cards, setCards] = useState([]);
useEffect(()=>{
for(let i = 0; i < 25; i++){
setCards((cards)=>[...cards, data.shift()]);
}
},[])
return(
<div className="mt-[5vh] grid grid-cols-[repeat(5,_minmax(10px,_1fr))] lg:grid-cols-[repeat(10,_minmax(10px,_1fr))] gap-1">
{
cards.map(el => {
return(<Card key={el.id} name={el.name} title={el.title} imageURL={el.imageURL} categories={el.categories} leaderSkill={el.leaderSkill} passive={el.passive} links={el.links}/>);
})
}
</div>
)
}
export default Cards;

Related

How to display dynamic text and images with sanity?

index.js export const
getServerSideProps = async () => {
const query = '*[_type == "product"]';
const products = await client.fetch(query);
const bannerQuery = '*[_type == "banner"]';
const bannerData = await client.fetch(bannerQuery);
return {
props: {products, bannerData}
}import { urlFor } from '../lib/client';
HeroBanner.JSX
const HeroBanner = ({heroBanner}) => {
return (
<div className='hero-banner-container'>
<div>
<p className='beats-solo'> {heroBanner.smallText} </p>
<h3> {heroBanner.midText} </h3>
<h1> {heroBanner.largeText1} </h1>
{console.log(heroBanner.largeText1)}
<img src={urlFor(heroBanner.image)} alt='Trending'
className='hero-banner-image' />
Client.js
import sanityClient from '#sanity/client';
import imageUrlBuilder from '#sanity/image-url';
export const client = sanityClient({
projectId:'*********',
dataset:'production',
apiVersion:'2022-12-04',
useCdn:true,
token:process.env.NEXT_PUBLIC_SANITY_TOKEN
});
const builder = imageUrlBuilder(client);
export const urlFor = (source) => builder.image(source);
This is the code here I tried. If normal text is in the p,h1, and h3 elements it works fine. However, the code I have there now is
{heroBanner.smallText} and that's where my problem starts. The text doesn't display when I use those values. I did change the values on sanity.io through localhost to what I want and nothing displays. P.S: When I console logged the bannerData I got the values I'm now trying to display.
sanity body text doesn't get displayed, you need to convert it using block-content
npm install #sanity/block-content-to-react --save
import SanityBlockContent from "#sanity/block-content-to-react";
then wrap the text you want to display in block-content.
As an example, post.body is what I want to display, it'll go something like this SanityBlockContent blocks={post.body} projectId="" dataset="*" />

React State and Arrays - Double rendering causes elements duplication

I am developing a fullstack blockchain Nft Dapp with React, Ethers and Solidity. I have made some routes and a mint page with wallet connection and mintbutton. Under the mint section there's the personal collection, where infos about property and metadata are retrieved from contract.
That's the collection component code.
import { useEffect, useState } from "react";
import Container from "react-bootstrap/Container";
import Row from "react-bootstrap/Row";
import Dino from "./Dino";
import { Contract, providers } from "ethers";
import { truncateAddress } from "./utils";
import { useWeb3React } from "#web3-react/core";
import { abi } from './abi';
export default function MyDinos() {
const { library, account} = useWeb3React();
const [dinosUri, setDinosUri] = useState([]);
const dinosTD = dinosUri.map((dino) => {
return (
<Dino key={dino} uriMetadata={dino} />
)
});
useEffect(() => {
if (!account) return;
if (!library) return;
const getDinosUri = async () => {
try {
const provider = await library.provider;
const web3Provider = new providers.Web3Provider(provider);
const signer = web3Provider.getSigner();
const contract = new Contract(process.env.REACT_APP_CONTRACT_ADDRESS, abi, signer);
const idArray = await contract.tokensOfWallet(account);
const idArrayFormatted = idArray.map(id => id.toNumber()).sort();
const uri = await contract.tokenURI(1);
const uriInPieces = uri.split("/");
const tmpDinos = [];
idArrayFormatted.forEach(id => {
const uriFormatted = `https://ipfs.io/ipfs/${uriInPieces[2]}/${id}`;
tmpDinos.push(uriFormatted);
//setDinosUri(prevArray => [...prevArray, uriFormatted])
});
setDinosUri(tmpDinos);
} catch (err) {
console.log(err);
}
}
getDinosUri();
return () => {
setDinosUri([]);
}
}, [library, account]);
return (
<>
{dinosUri.length > 0 &&
<div className='late-wow appear'>
<div className='svg-border-container bottom-border-light'></div>
<Container fluid className='sfondo-light py-4'>
<Container className='wow-container'>
<h2 className='wow appear mb-4 text-center'>Account: {truncateAddress(account)}</h2>
<h3 className='wow appear mb-4 text-center'>Dinos owned: {dinosUri.length} Dinos</h3>
<h4 className='wow appear mb-4 text-center'>Races won: COMING SOON</h4>
</Container>
</Container>
<div className='svg-border-container'></div>
<Container fluid className='sfondo-dark py-4'>
<Container>
<h2 className='mb-4'>My {dinosUri.length} Dinos</h2>
<Row className='my-5'>
{[...dinosTD]}
</Row>
</Container>
</Container>
</div>
}
</>
)
}
I managed to get the wanted result using a temporary variable tmpDinos to store the array of info, because if I used the commented method below //setDinosUri(prevArray => [...prevArray, uriFormatted]) on the first render I get the correct list, but if I change route and then get back to mint page, the collection is doubled. With the temp variable I cheated on the issue because it saves 2 times the same array content and it works good, but I don't think that's the correct React way to handle this issue. How can I get the previous code working? May it be a useEffect dependancy thing?
Thanks in advance for your attention.
A simple solution is to check if dinosUri is populated before setting its value.
if (dinosUri.length === 0) setDinosUri(prevArray => [...prevArray, uriFormatted])

Next.js Application error: a client-side exception has occurred (see the browser console for more information)

Seeing the above error when trying to load a page that renders product information that has been pulled from an external API. Error only occurs in production environment and everything runs fine locally. When checking the console I get this error:
TypeError: undefined is not a function (near '...n.map...')
"Next Build" works fine and builds a production build. "Next Start" works fine as well and there are no errors thrown in the console or anywhere else. Error only occurs once I have pushed to the production environment. Confused as to whats going on. I have my code below:
Component thats rendering the list of products:
import type { NextPage } from 'next'
import React, { useState, useEffect, useContext} from 'react';
import styles from '../styles/Home.module.css'
import DepopIcon from './icons/depop.svg'
import { Image, Main, Heading, Paragraph, Nav, Icons, Header, Grommet, Box, Button, Grid, Text, Footer, Anchor } from 'grommet';
import {
Instagram,
Shop,
Cart
} from 'grommet-icons';
import { useRouter } from 'next/router';
export default function ProductsList() {
const router = useRouter();
// load our products state variable
const [products, setProducts] = useState([]);
const [prodImg, setProdImg] = useState([]);
function handleProdClick(id){
router.push({ pathname: "/product", query: { id: id } })
}
const getProducts = async () => {
const response = await fetch("/api/getproducts");
var data = await response.json();
data = JSON.parse(data);
await setProducts(data);
}
useEffect(() => {
getProducts();
}, [])
//
// build areas list for our grid
const areaVar = "area";
const cols = 3;
var r = 0;
var c = 0;
var areas = []
for (let x = 1; x < products.length+1; x++){
const name = areaVar+x.toString()
areas.push({ name: name, start: [r,c], end: [r,c] })
r += 1
if (x % 3 == 0){
r = 0
c += 1
}
}
//
console.log(products);
// create our product objects for our grid
var productObjs = [];
if (typeof products != "undefined" && products != null){
productObjs = products.map((product, index) => {
return(
<Box
key={product._id}
gridArea= {areas[index].name}
background="#003311"
direction="column"
pad="none"
align="center"
onClick={() => {handleProdClick(product._id)}}
>
<Image
src={product.frontImage} fill={true} fit="cover"
onMouseOver={e => (e.currentTarget.src = product.backImage)}
onMouseOut={e => (e.currentTarget.src = product.frontImage)}
/>
<Box
direction="row"
pad="xsmall"
align="center"
gap="large"
justify="between"
animation="fadeIn"
>
<Text color="#fff" size="medium">{product.name}</Text>
<Text color="#fff" size="medium">{product.color}</Text>
<Text color="#fff" size="medium">{product.price} USD</Text>
<Text color="#fff" size="medium">{product.size}</Text>
</Box>
</Box>
);
});
}
//
const rows = []
for (let i = 0; i < r; i++){
rows.push('large')
}
return (
<Grid
rows={rows}
columns={['flex', 'flex', 'flex']}
gap="none"
areas={areas}
>
{productObjs}
</Grid>
);
}
Page that is using the above component:
import type { NextPage } from 'next'
import React, { useState, useContext, useEffect} from 'react';
import { Paragraph, Main, Nav, Icons, Header, Grommet, Box, Button, Grid, Text, Footer, Anchor } from 'grommet';
import ContactHeaderUnit from '../components/ContactHeaderUnit.tsx'
import FooterUnit from '../components/FooterUnit.tsx'
import ProductsList from '../components/ProductsList.tsx'
const Shop: NextPage = () => {
return (
<Grommet
full={true}
background="#fffced"
theme={{
global: { font: {
family: "Alice"
}},
paragraph: {
font: {
family: 'Arial',
},
},
label: {
font: {
family: 'Arial',
},
},
}}
>
<ContactHeaderUnit/>
<ProductsList/>
<FooterUnit/>
</Grommet>
)
}
export default Shop;
I had this error, even though I got no errors at build time, it was extremely difficult to figure out took a couple days. It turned out some of my incoming data was rendering into some invalid html (something was wrong with a dynamically created script tag). I was able to solve this error by trial and error removing different pieces of incoming data and seeing if my pages would render. Would start there if I had to do it again.
I had the same error, but there could be any reason, I would recommend to check your html tags first. It is also was useful to run app in dev mode and carefully look at the errors in console. In my case the problem was in the incorrect transfer of props from the parent component to child and than to subchild, I was passing the function call in props. Solved the problem by creating a function in the final child component without passing. I hope this helps.
I had this error, this what helped me in my project.
Screen from my Staging site (Heroku), (on Local there was no error)
on my local (dev mode) I have changed API to fetch from Staging site, rather Local (I am using Strapi CMS)
NEXT_PUBLIC_STRAPI_API='https://XXXXXXXXX.herokuapp.com/api'
My error on local, gave me more detailed error, Link in my case
To find where error was coming, in Layout.js file I uncommented one by one, 1) Header, 2) main, 3) Footer, it was Footer that generated error and fix Footer, no more error
From my experience with this error message in production, it usually because of trying to access a null object, undefined or even props/functions that are doesn't exist in the object.
One way to avoid these type of errors is to use typescript :)
For me, error was due to I missed environment variable on vercel dashboard. I only had .env file. After updating environment variable on dashboard, works fine.

movie-trailer npm isn't working properly in my netflix clone project

I've made a netflix clone using React.js, firebase, and have used TMDB api for movie database.
I've also used react-youtube and movie-trailer npm.
So it has this feature that every time I click on any movie poster, it's trailer must be played.
But for most of the movies, trailer doesn't shows up.
This is the error that I face -
movie-trailer: No TMDB Movie found with the current search terms, try searching https://www.themoviedb.org/search?query=Luis%20Miguel%3A%20The%20Series
TypeError: Failed to construct 'URL': Invalid URL
at Row.js:37
'This is the screenshot of errors I am facing on clicking maximum of movies'
I'm sharing the link of my github repo and deployed website as well for reference -
github - https://github.com/IshitaSharma3101/netflix-clone
website - https://netflix-clone-afb8b.web.app/
Row component code-
import React, { useState, useEffect } from "react";
import YouTube from "react-youtube";
import axios from "./axios";
import "./Row.css";
import movieTrailer from "movie-trailer"
const base_url = "https://image.tmdb.org/t/p/original/";
function Row({ title, fetchURL, isLargeRow }) {
const [movies, setMovies] = useState([]);
const [trailerURL, setTrailerURL] = useState("");
useEffect(() => {
async function fetchData() {
const request = await axios.get(fetchURL);
console.log(request.data.results);
setMovies(request.data.results);
return request;
}
fetchData();
}, [fetchURL]);
const opts = {
height: "390",
width: "100%",
playerVars: {
autoplay: 1,
},
};
const handleClick = (movie) => {
if (trailerURL) {
setTrailerURL("");
} else {
movieTrailer(movie?.name || movie?.title || movie?.original_title || "")
.then((url) => {
const urlParams = new URLSearchParams(new URL(url).search);
setTrailerURL(urlParams.get("v"));
})
.catch((error) => console.log(error));
}
};
return (
<div className='row'>
<h2>{title}</h2>
<div className='row__posters'>
{movies.map((movie) => (
<img
key={movie.id}
onClick={() => handleClick(movie)}
className={`row__poster ${isLargeRow && "row__posterLarge"}`}
src={`${base_url}${
isLargeRow ? movie.poster_path : movie.backdrop_path
}`}
alt={movie.name}
/>
))}
</div>
{trailerURL && <YouTube videoId={trailerURL} opts={opts} />}
</div>
);
}
export default Row;
I'm sure you are following the Clever Qazi tutorial as I'm doing. I think there is basically no solution for this problem. I also try to get the trailer of the movies by the ID that TMDB gives for every film but this method definitely doesn't work for mine. My conclusion is that movie-trailer is not working for certain kind of film or series...
You can prove yourself my conlclusion by typing on a terminal npx movie-trailer Cobra Kai
which is the command that allow you to use this package. Cobra Kai is a well know series but this "tool" doesn't find any trailer for it.
Use this instead.
movieTrailer(null ,{ tmdbId: movie.id })
.then((url)=>{
console.log("url is "+url);
const urlParams=new URLSearchParams(new URL(url).search);
console.log("urlParamsn"+urlParams);
setTrailerUrl(urlParams.get("v"));
})
.catch((error)=> console.log(error));
}
}
With this you can search for the movie with the tmdb id.
This error is coming becouse TMDB has not added ids for some videos if you want to play all video you just need need to change the genres of the Netflix Original Video from the path in request.js folder where you wrote your path becouse Netflix originals Videos has not linked with ids on TMDB.

Updating array using react hooks

I am making an application using the Upsplash API.
Upon rendering I want to display 30 images, witch works correctly.
import React, { useState, useEffect } from "react"
const ContextProvider =({ children }) =>{
const [allPhotos, setAllPhotos] = useState([])
const [cartItems, setCartItems] = useState([])
const [imageQuery, setImageQuery] = useState('')
useEffect(() => {
const url = `https://api.unsplash.com/photos?page=5&per_page=30&client_id=${process.env.REACT_APP_UNSPLASH_KEY}`
async function getPhotos() {
const photosPromise = await fetch(url)
const photos = await photosPromise.json()
setAllPhotos(photos)
}
getPhotos()
},[])
I then pass AllPhotos to my Photos.js using my context, and map over allPhotos, passing the photo to my Image component to display information about the image.
import React, {useContext} from "react"
import {Context} from "../Context"
function Photos(){
const {allPhotos} = useContext(Context)
const imageElements = allPhotos.map((photo,index) =>(
<Image key={photo.id} photo={photo}/>
))
return(
<>
<main>
{imageElements}
</main>
</>
)
}
export default Photos
const Image = ({ photo }) => {
return (
<div
<img src={photo.urls.thumb} className="image-grid" alt="" />
</div>
)
}
From here the images from the API display and everything is working correctly.
What I want to do now is add a search query, where the users can search for certain images.
I made a component for the input value
import React, { useContext } from "react"
import {Context} from "../../Context"
const QueryInput = () =>{
const {imageQuery, setImageQuery, SearchImage} = useContext(Context)
return(
<form onSubmit={SearchImage} >
<label>
Search Photos
<input
type="text"
className="query-input"
placeholder="Search Images"
value={imageQuery}
onChange={(e) => setImageQuery(e.target.value) }
/>
</label>
<button type="submit">Search Image</button>
</form>
)
}
export default QueryInput
I made a searchQuery function in my context
const SearchImage = async (e) =>{
e.preventDefault()
const queryUrl = `https://api.unsplash.com/search/photos?
age=5&per_page=30&query=${imageQuery}&client_id=${APP_KEY}`
const response = await fetch(queryUrl)
const queryPhotos = await response.json();
setAllPhotos(prevState => [...prevState, ...queryPhotos])
}
Everything works so far, I can console.log(queryPhotos) and get the users images of the query they searched for. If I search for "stars" I will get a bunch of images with stars.
What im having trouble doing is mapping through allPhotos again and displaying the query search images.
The error im having is
TypeError: queryPhotos is not iterable
I have been at this for awhile. Any information/advice would be greatly appreciated. Any questions about the code or need additional information I can provide it. THANK YOU.
In short.
queryPhotos is not an array.
unsplash api response for api /photos and /search/photos is a bit different. One return an array, while the other is an object, you need to access photos in results
So, change this line from
setAllPhotos(prevState => [...prevState, ...queryPhotos])
to
setAllPhotos(prevState => [...prevState, ...queryPhotos.results])
Should fix your problem.

Resources