I Use next 13 , I wanna add AOS library in my app and us it , I installed it , and added it properly to my component, but my component doesn't show and also I don't get any error.here is my Home Page code :
import Hero from "../components/index/Hero"
import ItSolutions from "#/components/index/ItSolutions"
import Skills from "#/components/index/Skills"
import Script from "next/script"
import AOS from 'aos';
import 'aos/dist/aos.css';
const getData = async (type) => {
const projectId = 'q8l0xi0c'
const dataset = 'production'
const query = encodeURIComponent(`*[_type == "${type}"]`)
const url = `https://${projectId}.api.sanity.io/v2021-10-21/data/query/${dataset}?
query=${query}`
const response = await fetch(url)
const data = (await response.json()).result
return data
}
const Home = async () => {
<Script>
AOS.init();
</Script>
const members = await getData('member')
const blogs = await getData('blog')
const customers = await getData('customer')
const solutions = await getData('solution')
return (
<div>
<Hero />
<ItSolutions solutions={solutions} />
<Skills />
</div>
)
}
export default Home
and I used this div for another component named Skills to apply AOS :
<div className="max-w-screen-xl mt-28 pt-36 px-4 pb-28 sm:px-16 md:px-8 lg:grid lg:grid-cols-2
lg:gap-20 lg:mt-16 xl:px-20 xl:mx-auto " data-aos="fade-up"> HI There
</div>
Related
I am developing a MERN stack app where I am trying to implement server side pagination.
Note that I am using React Query for managing server state.
On the root route, I display two posts.
When I click on the Next button, NEXT two blog posts should be displayed. However, this is not happening. I see the same two posts on page 2 as on page 1.
Where is the problem?
I think, there is either some problem with my server side pagination logic or with React Query. I suspect React Query is not fetching blog posts when I click on the Next button; instead it is fetching the posts from the cache. (I could be wrong here).
These are my code snippets:
postControllers.js
const asyncHandler = require("express-async-handler");
const Post = require("../models/postModel");
const fetchAllPosts = asyncHandler(async (req, res) => {
const { pageNumber } = req.body;
const pageSize = 2;
const postCount = await Post.countDocuments({});
const pageCount = Math.ceil(postCount / pageSize);
const posts = await Post.find({})
.limit(2)
.skip(pageSize * (pageNumber - 1));
res.json({ posts, pageCount });
});
postRoutes.js
const express = require("express");
const { fetchAllPosts, createPost } = require("../controllers/postControllers");
const router = express.Router();
router.get("/api/posts", fetchAllPosts);
module.exports = router;
Posts.js
import React, { useState } from "react";
import { useFetchAllPosts } from "../hooks/postsHooks";
import Spinner from "../sharedUi/Spinner";
const Posts = () => {
const [pageNumber, setPageNumber] = useState(1);
const { data, error, isLoading, isError } = useFetchAllPosts(pageNumber);
const handlePrevious = () => {
setPageNumber((prevPageNum) => prevPageNum - 1);
};
const handleNext = () => {
setPageNumber((prevPageNum) => prevPageNum + 1);
};
return (
<div>
{isLoading ? (
<Spinner />
) : isError ? (
<p>{error.message}</p>
) : (
data.posts.map((post) => (
<p className="m-6" key={post.title}>
{post.title}
</p>
))
)}
<div>
{isLoading ? (
<Spinner />
) : isError ? (
<p>{error.message}</p>
) : (
<div className="flex justify-between m-6 w-60">
<button
disabled={pageNumber === 1}
className="bg-blue-400 px-1 py-0.5 text-white rounded"
onClick={handlePrevious}
>
Previous
</button>
<p>{data.pageCount && `Page ${pageNumber} of ${data.pageCount}`}</p>
<button
disabled={pageNumber === data.pageCount}
className="bg-blue-400 px-1 py-0.5 text-white rounded"
onClick={handleNext}
>
Next
</button>
</div>
)}
</div>
</div>
);
};
export default Posts;
postHooks.js
import { useQuery, useMutation, useQueryClient } from "#tanstack/react-query";
import { useNavigate } from "react-router-dom";
import axios from "axios";
export const useFetchAllPosts = (pageNumber) => {
const response = useQuery(["posts"], async () => {
const { data } = await axios.get("/api/posts", pageNumber);
return data;
});
return response;
};
all dependencies of a query (= everything that is used inside the query function) needs to be part of the query key. React Query will only trigger auto fetches when the key changes:
export const useFetchAllPosts = (pageNumber) => {
const response = useQuery(["posts", pageNumber], async () => {
const { data } = await axios.get("/api/posts", pageNumber);
return data;
});
return response;
};
to avoid hard loading states between pagination, you might want to set keepPreviousData: true
see also:
the official pagination example
the guide on paginated queries
I am trying to make a counter that counts how many NFTs are minted.
I have an async function, getTotalTokensMinted, that gets the total number of tokens minted from a smart contract. How do I render the HTML so it displays the return value, numTokens, from getTotalTokensMinted? Should I use useState hook or local storage?
The code I have below returns a
Warning: Functions are not valid as a React child. This may happen if you return a Component instead of <Component /> from render
import React, { useEffect, useState } from 'react';
import { ethers } from 'ethers';
import './styles/App.css';
import myEpicNFT from './utils/MyEpicNFT.json';
const TOTAL_MINT_COUNT = 3;
const CONTRACTADDRESS = "0x6fe91f4814f372Eb40B547114CD75B76DF5f53dC";
const App = () => {
//const [NFTsMinted, NFTcounter] = useState(0);
const getTotalTokensMinted = async () => {
const { ethereum } = window;
let numTokens;
try {
if (ethereum) {
const provider = new ethers.providers.Web3Provider(ethereum);
const signer = provider.getSigner();
const connectedContract = new ethers.Contract(contractAddress, contractABI, signer);
numTokens = await connectedContract.getTokenNumber();
return numTokens;
}
} catch (error){
console.log(error);
}
return(
<div> {numTokens}</div>
);
}
return (
<div className="App">
<div className="container">
<p className = "sub-text">
NFT MINTED = {getTotalTokensMinted} / { TOTAL_MINT_COUNT }
</p>
</div>
</div>
</div>
);
}
Your code could quickly get confusing as you develop more functionality. As a rule of thumb, it's good to separate the business logic of your app from the UI.
Try putting your getTotalTokensMinted function in an /api folder or /utils. That function doesn't need to be a component; it simply needs to return a value...
const getTotalTokensMinted = async () => {
const { ethereum } = window;
let numTokens;
try {
if (ethereum) {
const provider = new ethers.providers.Web3Provider(ethereum);
const signer = provider.getSigner();
const connectedContract = new ethers.Contract(contractAddress, contractABI, signer);
numTokens = await connectedContract.getTokenNumber();
return numTokens;
}
return null
} catch (error){
console.log(error);
}
And then in the component you actually want to display the minted count you can simply declare a variable count (or whatever) which will store the number of tokens.
const App = () => {
const count = await getTotalTokensMinted();
return (
<div className="App">
<div className="container">
<p className = "sub-text">
NFT MINTED = {count} / { TOTAL_MINT_COUNT }
</p>
</div>
</div>
</div>
);
}
You may want to get the function returned value like this
return (
<div className="App">
<div className="container">
<p className = "sub-text">
NFT MINTED = {getTotalTokensMinted()} / { TOTAL_MINT_COUNT }
</p>
</div>
</div>
</div>
);
If you get an array object error you need to change on how you return the value in the function like this :
return (
<div> {numTokens?.map((each)=>{
<div>{each}</div>
})}
</div>
)
You need to wrap your component in the proper syntax:
example:
<Route exact path="/" element={Home}
Will give you this same error...Need to correct to this:
<Route exact path="/" element={}
From react point of view you want some async operation and its output in DOM. According to provided code snippet you are calling getTotalTokensMinted in the DOM with incorrect syntax. As a solution you need to call async function in useEffect hook with no dependency to render as componentDidMount. You need local state to store result and then use that state in the DOM.
Steps
Follow these steps as a solution
Define local state
By using useState you can create local state. You can use global state depends on the requirement
const [NFTsMinted, setNFTsMinted] = useState(0);
Async function
Set state in async function as follow
const getTotalTokensMinted = async () => {
const { ethereum } = window;
if (ethereum) {
const provider = new ethers.providers.Web3Provider(ethereum);
const signer = provider.getSigner();
const connectedContract = new ethers.Contract(contractAddress, contractABI, signer);
const numTokens = await connectedContract.getTokenNumber();
setNFTsMinted(numTokens)
}
}
Call async function
Use useEffect hook to call function
useEffect(() => {
getTotalTokensMinted()
}, [])
Display results in DOM
Use state variable to display counts
<div className="App">
<div className="container">
<p className = "sub-text">
NFT MINTED = {NFTsMinted} / { TOTAL_MINT_COUNT }
</p>
</div>
</div>
import { useSelector, useDispatch } from "react-redux";
import { useEffect, useState } from "react";
import { useHistory } from "react-router-dom";
import { IoMdArrowRoundBack } from "react-icons/io";
import axios from "axios";
import { fetchMovies } from "../../feautures/movies/moviesSlice";
import Rating from "../../components/UI/Rating/Rating";
import request from "../../requests";
import "./SingleMoviePage.scss";
import SimilarMovies from "../../components/SimilarMovies/SimilarMovies";
const SingleMoviePage = ({ match }) => {
const dispatch = useDispatch();
const [movieDetails, setMovieDetails] = useState({});
const [movieCredits, setMovieCredits] = useState({});
const history = useHistory();
console.log("single rendered")
// number month to string
const date = new Date(movieDetails.release_date);
const dateWithMonthName =
date.getFullYear() +
"-" +
date.toLocaleString("en-EN", { month: "long" }) +
"-" +
date.getDay();
/* params */
const movieId = match.params.id;
const page = match.params.page;
const genre = match.params.genre;
/* movies reducer handle */
const moviesStatus = useSelector((state) => state.movies.status);
/* base urls */
const baseImgUrl = "https://image.tmdb.org/t/p/original";
const movieDetailUrl = `https://api.themoviedb.org/3/movie/${movieId}?api_key=c057c067b76238e7a64d3ba8de37076e&language=en-US`;
const movieCastUrl = `https://api.themoviedb.org/3/movie/${movieId}/credits?api_key=c057c067b76238e7a64d3ba8de37076e&language=en-US`;
// go home page
const goHOme = () => {
history.goBack()
};
// fetch movie cast
useEffect(() => {
const fetchMovieCast = async () => {
let response = await axios.get(movieCastUrl);
response = response.data;
setMovieCredits(response);
};
fetchMovieCast();
}, [movieCastUrl]);
// fetch movie details
useEffect(() => {
const fetchMovieDetails = async () => {
let response = await axios.get(movieDetailUrl);
response = response.data;
setMovieDetails(response);
};
fetchMovieDetails();
}, [movieDetailUrl]);
let content;
if (moviesStatus === "loading") {
} else if (moviesStatus === "succeeded") {
content = (
<div
className="single-movie__container"
style={{
backgroundImage: `url(${
movieDetails.backdrop_path
? baseImgUrl + movieDetails.backdrop_path
: baseImgUrl + movieDetails.poster_path
})`,
}}
>
<div className="single-movie__details">
<IoMdArrowRoundBack
className="single-movie__back"
onClick={goHOme}
size={65}
color={"#e50914"}
/>
<h1 className="single-movie__title">{movieDetails.title}</h1>
<div className="single-movie__rate">
<Rating
rating={movieDetails.vote_average}
className="single-movie__stars"
/>
</div>
<p className="single-movie__overview">{movieDetails.overview}</p>
<div className="single-movie__informations single-movie__informations--genres">
<label className="single-movie__informations-heading">Genres</label>
<div className="single-movie__informations-container">
{movieDetails.genres?.map((genre) => {
return <div className="single-movie__info">{genre.name}</div>;
})}
</div>
</div>
<div className="single-movie__informations single-movie__informations--stars">
<label className="single-movie__informations-heading">
Starring
</label>
<div className="single-movie__informations-container">
{movieCredits.cast?.slice(0, 4).map((star) => {
return <div className="single-movie__info">{star.name}</div>;
})}
</div>
</div>
<div className="single-movie__informations single-movie__informations--released">
<label className="single-movie__informations-heading">
Release Date
</label>
<div className="single-movie__informations-container">
<div className="single-movie__info">{dateWithMonthName}</div>
</div>
</div>
<div className="single-movie__informations single-movie__informations--production">
<label className="single-movie__informations-heading">
Production
</label>
<div className="single-movie__informations-container">
{movieDetails.production_countries?.slice(0, 2).map((country) => {
return <div className="single-movie__info">{country.name}</div>;
})}
</div>
</div>
</div>
<SimilarMovies movieId={movieId} />
</div>
);
}
useEffect(() => {
if (genre === "POPULAR") {
dispatch(fetchMovies(request.fetchPopular(page)));
} else if (genre === "NOW PLAYING") {
dispatch(fetchMovies(request.fetchNowPlaying(page)));
} else if (genre === "UP COMING") {
dispatch(fetchMovies(request.fetchUpComing(page)));
}
}, [dispatch, genre, page]);
return <div className="single-movie">{content}</div>;
};
export default SingleMoviePage;
Hi all.When i clicked Card compenent it navigate me to the SingleMoviePage component.But SingleMoviePage component re-render five times.How can i find this issues's source ? And how can i prevent that ? Finally is there any problem to fetch MovieCast and MovieDetails in same useEffect hook ?
github repo : https://github.com/UmutPalabiyik/hope-movie-app
demo : https://hope-movie.web.app/page/1
The first 2 useEffect hooks fetch data separately which then update your local states, which then triggers re-rendering.
If you don't want to re-render after each data fetch (state update), I'd suggest adding a loading state. Set it to true first and return a loading icon as your content. Then after both movieDetails and movieCredits have been populated, set it to false and return the actual content. This should render twice in total.
Have you considered graphql? GraphQL can combine your api calls into one and it also handles loading state and error state.
Whatever solution you have, re-rendering will happen when you are fetching data. Initial render won't have any data and after fetching data it must re-render.
You should use only one useEffect hook your code is running for all three. React will handle the rest itself.
// Edit --
This may help:
Project Hatchways
Link to issue -
Issue
As the codes stands right now, the results from the tags still aren't rendering results.
I have a component App.js that renders some children. One of them is 2 search bars. The second search bar TagSearch is supposed to render results from tag creation. What I'm trying to do is pass data from Student where the tags live, and pass them up to the App component in order to inject them into my Fuse instance in order for them to be searched. I have tried to create a function update in App.js and then pass it down to Student.js in order for the tags to update in the parent when a user searches the tags. For some reason, I'm getting a TypeError that states update is not a function.
I put in console logs to track where the tags appear. The tags appear perfectly fine in Student.js, but when I console log them in App.js, the tags just appear as an empty array which tells me they aren't being properly passed up the component tree from Student.js to App.js.
// App.js
import axios from "axios";
import Fuse from "fuse.js";
import Student from "./components/Student";
import Search from "./components/Search";
import TagSearch from "./components/TagSearch";
import "./App.css";
function App() {
const [loading, setLoading] = useState(true);
const [students, setStudents] = useState([]);
const [query, updateQuery] = useState("");
const [tags, setTags] = useState([]);
const [tagQuery, setTagQuery] = useState("");
console.log("tags from app: ", tags);
const getStudents = async () => {
setLoading(true);
try {
const url = `private url for assignment`;
const response = await axios.get(url);
setStudents(response.data.students);
setLoading(false);
} catch (err) {
console.log("Error: ", err);
}
};
const fuse = new Fuse(students, {
keys: ["firstName", "lastName"],
includeMatches: true,
minMatchCharLength: 2,
});
const tagFuse = new Fuse(tags, {
keys: ["text", "id"],
includesMatches: true,
minMatchCharLength: 2,
});
function handleChange(e) {
updateQuery(e.target.value);
}
function handleTags(e) {
setTagQuery(e.target.value);
}
const results = fuse.search(query);
const studentResults = query ? results.map((s) => s.item) : students;
const tagResults = tagFuse.search(tagQuery);
const taggedResults = tagQuery ? tagResults.map((s) => s.item) : tags;
const update = (t) => {
t = tags; // changed this to make sure t is tags from this component's state
setTags(t);
};
useEffect(() => {
getStudents();
}, []);
if (loading) return "Loading ...";
return (
<div className="App">
<main>
<Search query={query} handleChange={handleChange} />
<TagSearch query={tagQuery} handleTags={handleTags} />
{studentResults &&
studentResults.map((s, key) => <Student key={key} students={s} update={update} />)}
{taggedResults &&
taggedResults.map((s, key) => (
<Student key={key} students={s} update={update} />
))}
</main>
</div>
);
}
export default App;
// Student.js
import Collapsible from "../components/Collapsible";
import findAverage from "../helpers/findAverage";
import Styles from "../styles/StudentStyles";
const KeyCodes = {
comma: 188,
enter: 13,
};
const delimiters = [KeyCodes.comma, KeyCodes.enter];
const Student = ({ students, update }) => {
const [isOpened, setIsOpened] = useState(false);
const [tags, setTags] = useState([]);
const collapse = () => {
setIsOpened(!isOpened);
};
const handleDelete = (i) => {
const deleted = tags.filter((tag, index) => index !== i);
setTags(deleted);
};
const handleAddition = (tag, i) => {
setTags([...tags, tag]);
};
useEffect(() => {
update(tags);
}, []);
return (
<Styles>
<div className="student-container">
<img src={students.pic} alt={students.firstName} />
<div className="student-details">
<h1>
{students.firstName} {students.lastName}
</h1>
<p>Email: {students.email}</p>
<p>Company: {students.company}</p>
<p>Skill: {students.skill}</p>
<p>Average: {findAverage(students.grades)}</p>
<Collapsible
students={students}
delimiters={delimiters}
handleDelete={handleDelete}
handleAddition={handleAddition}
isOpened={isOpened}
tags={tags}
/>
</div>
</div>
<button onClick={collapse}>+</button>
</Styles>
);
};
export default Student;
Ciao, try to call update function every time you update tags in Student. Something like this:
const handleDelete = (i) => {
const deleted = tags.filter((tag, index) => index !== i);
setTags(deleted);
update(deleted);
};
const handleAddition = (tag, i) => {
let result = tags;
result.push(tag);
setTags(result);
update(result);
};
In this way, every time you change tags in Student, you will update App state.
An alternative could be use useEffect deps list. In Student, modify useEffect like this:
useEffect(() => {
update(tags);
}, [tags]);
This means that, every time tags will update, useEffect will be triggered and update function will be called.
I am trying to fetch images by their ids. The architecture of backend is as follows: DB stores images in binary and there is another table that stores images ids.
I am using apollo client on front end to prefetch images ids and then send another set of fetch requests.
Unfortunately I get Error: Too many re-renders. React limits the number of renders to prevent an infinite loop. Could anyone help me to
1) figure out why it happens. I see that there is bunch of pending promises in the stack.
and 2) how it can be refactored to better architecture.
import React, {useState} from 'react'
import {useQuery} from "#apollo/react-hooks";
import {gql} from 'apollo-boost';
const apiEndpoint = 'http://localhost:9211';
const getProductImage = function (id) {
return gql`
{
productById(id: "${id}") {
images {
imageId
}
}
}`
};
const fetchImage = (imageUrl, allImgsArr) => {
return fetch(imageUrl)
.then(res => res.blob())
.then(img => allImgsArr.push(URL.createObjectURL(img)))
};
const ItemPage = (props) => {
const [id] = useState(props.match.params.id);
const {data} = useQuery(getProductImage(id));
let imagesIds = [];
if (data) {
data.productById.images.forEach(image => {
imagesIds.push(image.imageId)
});
}
const [imagesUrls, setImagesUrl] = useState([]);
// MULTIPE FETCH RETRIEVALS START
for (let imId of imagesIds) {
setImagesUrl(imagesUrls => [...imagesUrls, fetchImage(`${apiEndpoint}/image/${imId}`, imagesUrls)]);
}
// MULTIPE FETCH RETRIEVALS END
return (
<>
<div>
<div>
<img src={imagesUrls[0] ? imagesUrls[0] : ''} alt="main item 1 photo"/>
</div>
<div>
<div>
<img src={imagesUrls[1] ? imagesUrls[1] : ''} alt="Additional item 1 photo"/>
</div>
</div>
</div>
</>
)
};
export default ItemPage;
your query should be a constant , not function.
const GET_PRODUCT_IMAGE = gql`
query getProduct($id:String!) {
productById(id: $id) {
images {
imageId
}
}
}
}`
// pass variables like this
const {data} = useQuery(GET_PRODUCT_IMAGE, { variables: { id },
});
More Info : https://www.apollographql.com/docs/react/data/queries/