I have displayed all the anime images from api, now I want if any anime result is clicked then it should open details for that particular anime. I have created component Details where I want to send details of anime.
how can I send details of anime to the component Details ?
Here is my code:
import { useEffect, useState } from 'react';
import './CSS/style.css';
import Details from './components/Details';
function App() {
const [user, setUser] = useState([])
const getUsers = async () =>{
const response = await fetch('https://ghibliapi.herokuapp.com/films')
setUser(await response.json());
}
useEffect(() => {
getUsers();
}, []);
const getDetail = (e) =>{
// what should I write here to pass props on component < Details />
console.log(e)
}
return (
<>
<h2>Anime World</h2>
<div className="container-fluid mt-5">
<div className="row text-center">
{
user.map((curElem) => {
return (
<div className="col-10 col-md-4 mt-5" key={curElem.id} >
<div className="card">
<img src={curElem.image} className="card-img-top imageSize" alt="..."/>
<div className="card-body">
<h5 className="card-title">{curElem.title} </h5>
<button onClick={getDetail} >Get Detail</button>
</div>
</div>
</div>
)
})
}
</div>
</div>
</>
);
}
export default App;
Dummy values are given to component Details right now, I have to get correct value from props.
import React from 'react';
import './details.css';
function Details() {
return (
<>
<h2>Information of Anime</h2>
<div className="container-fluid mt-5">
<div className="row text-center">
<div className="col-10 col-md-8 mx-auto" >
<div className="card box">
<img src= '...' className="card-img-top imageSize" alt="..."/>
<div className="card-body">
<div className='details'>
<h5><span>Title:</span> Title</h5>
<h5><span>Original Title:</span> Original Title</h5>
<h5><span>Director:</span> Director</h5>
<h5><span>Producer:</span> Producer</h5>
<h5><span>Release Date:</span> date</h5>
<h5><span>Running time:</span> time</h5>
<h5><span>Description:</span> <p> Description</p></h5>
</div>
</div>
</div>
</div>
</div>
</div>
</>
)
}
export default Details;
I'm going to assume that the list you receive from the API is the list of each anime, and when you click you want to render the selected anime using the Details component. If that's the case this is my approach
import { useEffect, useState } from 'react';
import './CSS/style.css';
import Details from './components/Details';
function App() {
const [user, setUser] = useState([]);
const [anime, setAnime] = useState(null);
const getUsers = async () =>{
const response = await fetch('https://ghibliapi.herokuapp.com/films');
setUser(await response.json());
};
useEffect(() => {
getUsers();
}, []);
const getDetail = (anime) =>{
setAnime(anime);
};
return (
<>
<h2>Anime World</h2>
<div className="container-fluid mt-5">
<div className="row text-center">
{user.map((elem) => (
<div className="col-10 col-md-4 mt-5" key={curElem.id}>
<div className="card">
<img src={elem.image} className="card-img-top imageSize" alt="..."/>
<div className="card-body">
<h5 className="card-title">{elem.title} </h5>
<button onClick={() => getDetail(elem)} >Get Detail</button>
</div>
</div>
</div>
))}
</div>
</div>
{anime && <Details {...anime} />}
</>
);
}
export default App;
So basically what I'm doing here is rendering <Details /> only when an anime element is in state. If it's null it won't render the component.
Secondly I'm spreading the selected element into the Details component, so that inside the component you can access each property like this:
import React from 'react';
import './details.css';
function Details(props) {
const { title } = props; // each prop is each property of the selected anime
return (
<>
<h2>Information of Anime</h2>
<div className="container-fluid mt-5">
<div className="row text-center">
<div className="col-10 col-md-8 mx-auto" >
<div className="card box">
<img src= '...' className="card-img-top imageSize" alt="..."/>
<div className="card-body">
<div className='details'>
<h5><span>Title:</span> {title}</h5>
<h5><span>Original Title:</span> Original Title</h5>
<h5><span>Director:</span> Director</h5>
<h5><span>Producer:</span> Producer</h5>
<h5><span>Release Date:</span> date</h5>
<h5><span>Running time:</span> time</h5>
<h5><span>Description:</span> <p> Description</p></h5>
</div>
</div>
</div>
</div>
</div>
</div>
</>
)
}
export default Details;
Related
I'm new in next js and I'm working on project using NextJS. I have some lots in my items page that shows lots currently(pagination/items.tsx) and I also have lotDetails page that I want it to show details of each lot using dynamic route(lotDetails\id\index.tsx).
This is the folder structure:
Now when I click the Link in Items.tsx I expect it to go to lotDetails page and pass the props, but nothing happens! (It stays on Items page!). here is Items.tsx:
import React from 'react'
import Link from "next/link"
const Items = ({currentItems}:{currentItems:any}) => {
console.log(currentItems)
// const ids=currentItems.map((el:any)=>el.id)
// const paths=ids.map((el:any)=>{params:{id:el.toString()}})
// console.log(paths)
return (
<>
<div className="container">
<div className="row">
{currentItems.map((el:any)=><div className="col-md-3 ">
//this should be linked to lotDetails page!
<Link href={{pathname:"../lotDetails/[id]",query:{id:JSON.stringify(el.id),title:el.title,image:el.image,description:el.description.toString(),rate:el.rating.rate,count:el.rating.count,price:el.price},}} as={`/lotDetails/${el.id.toString()}`}>
<div className="lot">
<div className="img-container">
<img src={el.image}/>
</div>
<div className="title">
{el.title}
</div>
<div className="price">
<span className="price-title">Price:</span>
<span>{el.price}</span>
</div>
</div>
</Link>
</div>)}
</div>
</div>
</>
)
}
export default Items;
I'm using getStaticProps and GetStaticPaths in lotDetails:
const LotDetails = (props:any) => {
const dispatch=useDispatch();
console.log(props)
const lotCount=1;
const addLots=()=>{
dispatch(AddCustomerLot({...props,lotCount:lotCount}))
}
return (
<>
<div className='container lot-details'>
<div className="row" >
<div className="col-md-6">
<div className="detail-container">
<div className="title-details"><h3>{props.title}</h3></div>
<div className="badge"><FontAwesomeIcon icon={faStar}/><span>{props.rate}</span></div>
<div className="inventory">
Inventory: <span className="count">{props.count}</span>
</div>
<div className="description-details">{props.description}</div>
<div className="price">Price: <span className="price-number">{props.price}$</span> </div>
<button className="btn btn-regist" onClick={addLots}>Add to shopping basket</button>
</div>
</div>
<div className="col-md-6"><img src={props.image} alt="" /></div>
</div>
</div>
</>
)
}
export const getStaticPaths:GetStaticPaths=async(context:any)=>{
const response= await axios.get("https://fakestoreapi.com/products")
const paths=response.data.map((el:any)=>({params:{id:el.id.toString()}}))
console.log(paths)
return{
paths,
fallback:'blocking'
}
}
export const getStaticProps:GetStaticProps=async(context:any)=>{
return{
props:
{
//recieve props
id:context.query.id,
title:context.query.title,
image:context.query.image,
description:context.query.description,
rate:context.query.rate,
count:context.query.count,
price:context.query.price
}
}
}
export default LotDetails;
when I deleted getStaticProps and getStaticPaths, the link worked! So I receive that link works perfectly and the problem is in getStaticProps and getStaticPaths. Of course I don't want to use getServerSideProps.
Update
According to julio's suggestion I changed pathName, and I also changed context.query to context.params.id:
Items:
<Link href={{pathname:`/lotDetails/${el.id}`,query:{id:JSON.stringify(el.id),title:el.title,image:el.image,description:el.description.toString(),rate:el.rating.rate,count:el.rating.count,price:el.price},}} as={`/lotDetails/${el.id.toString()}`}>
<div className="lot">
<div className="img-container">
<img src={el.image}/>
</div>
<div className="title">
{el.title}
</div>
<div className="price">
<span className="price-title">Price:</span>
<span>{el.price}</span>
</div>
</div>
</Link>
lotDetails:
return (
<>
<div className='container lot-details'>
<div className="row" >
<div className="col-md-6">
//I removed all section which used props and querys using comments
{/* <div className="detail-container">
<div className="title-details"><h3>{props.title}</h3></div>
<div className="badge"><FontAwesomeIcon icon={faStar}/><span>{props.rate}</span></div>
<div className="inventory">
Inventory: <span className="count">{props.count}</span>
</div>
<div className="description-details">{props.description}</div>
<div className="price">Price: <span className="price-number">{props.price}$</span> </div>
<button className="btn btn-regist" onClick={addLots}>Add to shopping basket</button>
</div> */}
</div>
{/* <div className="col-md-6"><img src={props.image} alt="" /></div> */}
</div>
</div>
</>
)
}
export const getStaticPaths:GetStaticPaths=async(context:any)=>{
const response= await axios.get("https://fakestoreapi.com/products")
const paths=response.data.map((el:any)=>({params:{id:el.id.toString()}}))
console.log(paths)
return{
paths,
fallback:'blocking'
}
}
export const getStaticProps:GetStaticProps=async(context:any)=>{
return{
props:
{
id:context.params.id,
// title:context.query.title,
// image:context.query.image,
// description:context.query.description,
// rate:context.query.rate,
// count:context.query.count,
// price:context.query.price
}
}
}
Finally, I solved problem in two steps:
1-I'm using google chrome browser, so I configured chrome and added my localhost port:
I used this link: chrome://inspect/, clicked configure button and added my localhost port(in my case localhost:3000)
2-I added this code to lotDetails page(the page which I used axios)
axios.defaults.httpsAgent=new https.Agent({
rejectUnauthorized:false,
})
don't forget to import:
import https from "https"
Now It's working.
Trying to make a movie app but the type won't let me take the arguments and display them (using typescript).The problem is that I am trying to map the movie Object and display them one by one to homepage and show all the movies that I got. Also I use api from themoviedb.
This is the movie script
import React, { useEffect, useRef, useState } from "react";
import { KeyObject } from "tls";
const IMG_API="ImageApi";
interface movie{
title: string;
path: path.ParsedPath;
overview: string;
voteavg: string;
key: KeyObject;
}
const Movie=(movie:movie)=>{
<div className="movie">
<img src={IMG_API+movie.path} alt={movie.title} />
<div className="info">
<h3>{movie.title}</h3>
<span>{movie.voteavg}</span>
</div>
<div className="overview">
<h2>Overview</h2>
<p>{movie.overview}</p>
</div>
</div>
}
export default Movie;
This is the home page script.
import NavigationBar from "../NavigationBar/NavigationBar";
import Movie from "../Movie";
import React, { useEffect, useRef, useState } from "react";
const FEATURED_API="baseUrl+apiKey";
const HomePage= () =>{
const movieElement=useRef(new Array());
const [movies,setMovie]=useState([]);
useEffect(()=>{
fetch(FEATURED_API).then((res)=>res.json)
.then(data=>{
setMovie(data.arguments);
});
},[]);
return(
<>
<div className="header">
<header>Welcome to the cinema</header>
<NavigationBar/>
</div>
<div className="movie-container">
{movies.map((movie)=><Movie key={movie} {...movies}/>)}
</div>
</>
);
}
const HomePage= () =>{
const movieElement=useRef(new Array());
const [movies,setMovie]=useState([]);
useEffect(()=>{
fetch(FEATURED_API).then((res)=>res.json)
.then(data=>{
setMovie(data.arguments);
});
},[]);
return(
<>
<div className="header">
<header>Welcome to the cinema</header>
<NavigationBar/>
</div>
<div className="movie-container">
{movies.map((movie)=><Movie key={movie} {...movies}/>)}
</div>
</>
);
}
When your function body has ( ) ie. round(parenthesis) brackets, the return is implicit. ie. whatever is in the curly braces will be returned automatically
const Movie=(movie:movie)=>(
<div className="movie">
<img src={IMG_API+movie.path} alt={movie.title} />
<div className="info">
<h3>{movie.title}</h3>
<span>{movie.voteavg}</span>
</div>
<div className="overview">
<h2>Overview</h2>
<p>{movie.overview}</p>
</div>
</div>
)
When your function body has a { } ie. curly brackets, you have to explicit use the return keyword to return something
const Movie=(movie:movie)=>{
return (
<div className="movie">
<img src={IMG_API+movie.path} alt={movie.title} />
<div className="info">
<h3>{movie.title}</h3>
<span>{movie.voteavg}</span>
</div>
<div className="overview">
<h2>Overview</h2>
<p>{movie.overview}</p>
</div>
</div>
)
}
In the below code, if you have used {}, then you will have to manually return the JSX as :
const Movie=(movie:movie)=>{
return (
<div className="movie">
<img src={IMG_API+movie.path} alt={movie.title} />
<div className="info">
<h3>{movie.title}</h3>
<span>{movie.voteavg}</span>
</div>
<div className="overview">
<h2>Overview</h2>
<p>{movie.overview}</p>
</div>
</div>
)
}
This is what it is complaining about, if you were not using {} then it would have returned it auto using ES6 short form of arrow functions.
I have a react code here
i want to load data from an API but it's taking time to get the data, thus my function is failing
How do i set it that it should wait for the data before rendering
import Head from 'next/head'
import Link from 'next/link'
import Navbar from './Navbar'
import Template from './Template'
import { useState, useEffect } from 'react'
export async function getStaticProps() {
const response = await fetch('https://peegin.com/api/public/peegins/recent')
const data = await response.json()
return {
props: { data }
}
}
const Home = ({ data }) => {
return (
<div className="content">
<Head>
<title>Peegin Recent</title>
</Head>
<Navbar />
{title}
{data.map(peegin => (
<div className="preview" key={peegin.permalink}>
<h3 className="title">
{peegin.title}
</h3>
<p>{peegin.meaning}</p>
<p className="example">Example</p>
<p className="example-content">{peegin.example}</p>
<p className="origin">Origin: {peegin.origin}</p>
<div className="name">
<h4>By</h4> <h4 className="namegreen">{peegin.user.name}</h4> <h4>{peegin.created_at}</h4>
</div>
<p className="views">{peegin.views.view} Views</p>
</div>
))}
</div>
);
}
export default Home;
const Home = ({ data }) => {
// add this as fallback
if(!data){
return <h1>Loading..<h1/>
}
return (
<div className="content">
<Head>
<title>Peegin Recent</title>
</Head>
<Navbar />
{title}
// add this to check for data first then do map
{data && data.map(peegin => (
<div className="preview" key={peegin.permalink}>
<h3 className="title">
{peegin.title}
</h3>
<p>{peegin.meaning}</p>
<p className="example">Example</p>
<p className="example-content">{peegin.example}</p>
<p className="origin">Origin: {peegin.origin}</p>
<div className="name">
<h4>By</h4> <h4 className="namegreen">{peegin.user.name}</h4> <h4>{peegin.created_at}</h4>
</div>
<p className="views">{peegin.views.view} Views</p>
</div>
))}
</div>
);
}
Before this, I'm using Snapshot and try to map it. But it failed for a single document. After I read back the documentations from firebase. They recommend using this way for a single document. But I don't know how to make it readable on the site rather than console. I want to send data on the title and essay.
const { id } = useParams()
useEffect(() => {
db.collection("posts").doc(id).get().then(doc => {
const newData = doc.data();
console.log(newData);
});
}, []);
return (
<div className="log">
<article className="log-details">
<div className="author-pic clearfix">
<img src={profile} alt="" />
</div>
<div className="log-preview">
<div class="cover"></div>
<h2 className="title clearfix">title here</h2>
<div className="details ">
<img src={One} alt="" />
<p className="essay">essay here</p>
</div>
</div>
</article>
</div>
)
To display the post Data use useState and set the postData with setPostData(newData). Then you can read the postData values with {postData.title} and {postData.essay} in the return statement.
Dont forget to import useState with import React, { useState, useEffect } from "react".
const { id } = useParams()
const [postData, setPostData] = useState("");
useEffect(() => {
db.collection("posts").doc(id).get().then(doc => {
const newData = doc.data();
setPostData(newData);
console.log(newData);
});
}, []);
return (
<div className="log">
<article className="log-details">
<div className="author-pic clearfix">
<img src={profile} alt="" />
</div>
<div className="log-preview">
<div class="cover"></div>
<h2 className="title clearfix">{postData && postData.title}</h2>
<div className="details ">
<img src={One} alt="" />
<p className="essay">{postData && postData.essay}</p>
</div>
</div>
</article>
</div>
)
I have 2 components as below. When I try to pass a method (increment) from the component 'CartList' to 'CartItem' it says increment is undefined. The error occurs when I click on the button (Pointed in the below code). How can I solve this error?
Parent
import React, {Component} from 'react';
import CartItem from './CartItem';
import {connect} from "react-redux";
import Axios from "axios";
const mapStateToProps = ({ session}) => ({
session
});
const CartList = ({session, ...props}) => {
const cart = props.cart;
const increment = (productId) => {
const item = {
userId : session.userId,
productId: productId
};
Axios.post('http://localhost:5000/api/cart/increment', item)
.then(res=>{
if(res.status === 200){
console.log('Incremented');
}
})
};
return (
<div className="container-fluid">
{cart.map(item => {
return <CartItem key = {item.id} item={item} increment={increment}/>
})}
</div>
);
};
export default connect(
mapStateToProps
)(CartList);
Child
import React from 'react';
import {connect} from "react-redux";
const mapStateToProps = ({ session}) => ({
session
});
const CartItem = ({session ,...props}) => {
const {id,name, price, quantity} = props.item;
const {increment} = props.increment;
return (
<div className="row my-2 text-capitalize text-center">
<div className="col-10 mx-auto col-lg-2">
<img style={{width: '5rem', height: '5rem'}} className="img-fluid" alt="product "/>
</div>
<div className="col-10 mx-auto col-lg-2">
<span className="d-lg-none">Product: </span>{name}
</div>
<div className="col-10 mx-auto col-lg-2">
<span className="d-lg-none">Price: </span>{price}
</div>
<div className="col-10 mx-auto col-lg-2 my-2 my-lg-0">
<div className="d-flex justify-content-center">
<div>
<span className="btn btn-black mx-1" >-</span>
<span className="btn btn-black mx-1">{quantity}</span>
<span className="btn btn-black mx-1" onClick={() => increment(id)}>+</span> //<- Error occurs if I click on this button
</div>
</div>
</div>
<div className="col-10 mx-auto col-lg-2">
<div className="cart-icon" >
<i className="fas fa-trash"/>
</div>
</div>
<div className="col-10 mx-auto col-lg-2">
<srong>Total: ${50}</srong>
</div>
</div>
);
};
export default connect(
mapStateToProps
)(CartItem);
I tried implementing the function directly in the child component it is working fine. This method is responsible for incrementing the quantity of a product in the database(MongoDB). But updated value does not display. Because of that I implemented the 'increment' function within the parent component
The issue is this line:
const {increment} = props.increment;
That is trying to access props.increment.increment, which is undefined. You either meant to do
const increment = props.increment;
or
const {increment} = props;
Hi Please replace this line
Because when you destructuring props you don't need map key from props
for better understanding console your props or have a look at this document.
https://medium.com/#lcriswell/destructuring-props-in-react-b1c295005ce0
const {increment} = props.increment;
instead of
const {increment} = props;
I hope it works.
Thanks