Data passing probelm between files in next js - html

So i have three files here :-
project.js
import Image from 'next/image';
import Link from 'next/link'
import { DATA } from '../../components/Data'
const WEB_RELATED = []
const PC_EXES = []
for(let i=0;i<DATA.length; i++){
if(DATA[i]['loc'] == 'WEB'){
WEB_RELATED.push(DATA[i])
}
else if(DATA[i]['loc'] == 'EXE'){
PC_EXES.push(DATA[i])
}
}
const WEB = WEB_RELATED.map(item =>
<div className="PROJECTS_Projects">
<div className="PROJECTS_Projects_Image">
<Image
className='PROJECTS_Projects_image'
src={item['img']}
layout='fill'
// objectFit='contain'
/>
</div>
{/* if someone clicks on this link i want them to go to [project].js and send This item to [projcet].js */}
<Link href={'/projects/' + WEB_RELATED.indexOf(item)}>
<a>{item['title']}</a>
</Link>
<p>{item['desc']}</p>
</div>
);
const PC = PC_EXES.map(item =>
<div className="PROJECTS_Projects">
<div className="PROJECTS_Projects_Image">
<Image
className='PROJECTS_Projects_image'
src={item['img']}
layout='fill'
// objectFit='contain'
/>
</div>
{/* if someone clicks on this link i want them to go to [project].js and send This item to [projcet].js */}
<Link href={'/projects/' + PC_EXES.indexOf(item)}>
<a>{item['title']}</a>
</Link>
<p>{item['desc']}</p>
</div>
);
export default function index() {
return (
<div className="PROJECTS_Container">
<div className="PROJECTS_Sub_Container">
<div className="PROJECTS_New">
<h1>Web-Related</h1>
<div className="PROJECTS_Present">
{WEB}
</div>
</div>
<div className="PROJECTS_New">
<h1>Pc apllications</h1>
<div className="PROJECTS_Present">
{PC}
</div>
</div>
</div>
</div>
)
}
Project Display page [project.js]
import { useRouter } from 'next/router'
import { useState } from 'react';
import Image from 'next/image';
import { DATA } from '../../components/Data';
import React, {useEffect} from 'react';
export default function title() {
const router = useRouter();
const { project } = router.query
const [state, setState] = useState()
// when user comes here i want the item sent to be read and injected into the html
useEffect(() => {
// project && console.log('value', project, 'length : ', project.length);
// setState(project)
console.log(DATA[project]['loc'])
}, [router])
return (
<div className='DISPLAY_Container'>
<div className="DISPLAY_Sub_Container">
<div className="DISPLAY_Image">
<Image
src={'/img/Projects/Cluq.PNG'}
layout='fill'
/>
</div>
<div className="DISPLAY_Info">
<h3>{state}</h3>
SUS
<p>lorem300</p>
</div>
</div>
</div>
)
}
DATA.JS file where i've kept all of the objects i want to be shown
export const DATA = [
{
'loc':'WEB',
'title':"Bukkit List",
'img':'/img/Projects/Bukkit-List.PNG',
'desc':"Bukkit-List is a easy to use and free task managing webapp, with password protection now!",
'fullDesc':""
},
{
'loc':'WEB',
'title':"SilenxIka-Github",
'img':'/img/Projects/SilenxIkaGithub.PNG',
'desc':"First github website for Project SilenxIka, which is completly made from vanilla HTML/CSS/JS",
'fullDesc':""
}
]
when someone presses a link in the first file (check there are coments above the link) the item in the link shall be passed to the second file and i can use the item in [project].js file to inject it into the html

You can append query parameters to your url and use the useRouter hook from "next/router" for getting the content of those query parameters in your other file.
Let's imagine your item object has an id and we want to append that id as a query parameter to your route:
In project.js:
export const arrayOfItems = [
{id: 'A', title: 'A title'},
{id: 'B', title: 'B title'},
{id: 'C', title: 'C title'},
{id: 'D', title: 'D title'},
];
// Add query param "item_id" plus the id of your item to your url (note the '?')
{arrayOfItems.map((item)=>
<Link href={'/projects?item_id= + item.id }>
<a>{item.title}</a>
</Link>
)
In your product display page:
import { useRouter } from "next/router";
import { arrayOfItems } from "./project.js"; // path to where array is exported from
const ProductPage = () => {
const router = useRouter();
useEffect(() => {
// here you have access to the query parameters
console.log(router.query?.item_id);
// get item_id from route
const routeItemId = router.query?.item_id;
// search through array and find item with matching id
const matchingItem = arrayOfItems.find((item)=> item.id === routeItemId && item);
console.log(matchedItem);
}, [router]);
return(<></>)
}

Related

Image doesn't show up in react render

I want to add an image in a tinder-clone app. I followed the mern stack tutorial on the clever programmer youtube channel. Unfortunately, the image didn't show up in the browser.
This is my code:
import React, { useState } from 'react';
import "./TinderCards.css";
import TinderCard from 'react-tinder-card';
function TinderCards() {
const [people, setPeople] = useState([
{
name: 'Elon Musk',
url: "https://upload.wikimedia.org/wikipedia/commons/3/34/Elon_Musk_Royal_Society_%28crop2%29.jpg",
},
]);
const swiped =(direction, nameToDelete) => {
console.log("removing: " + nameToDelete);
};
const outOfFrame = (name) => {
console.log(name + "left the screen!");
};
return (
<div className="tinderCards">
<div className="tinderCards__cardContainer">
{people.map(person => (
<TinderCard
className="swipe"
key={person.name}
preventSwipe= {["up", "down"]}
onSwipe={(dir) => swiped(dir, person.name)}
onCardLeftScreen={() => outOfFrame(person.name)}
>
<div
style={{ backgroundImage: 'url(${person.url})' }}
className="card"
>
<h3>{person.name}</h3>
</div>
</TinderCard>
))}
</div>
</div>
);
}
export default TinderCards
And this is what I see in the browser:
tinder clone

Ionic Route replace Url without page animation

Im about to setup a product Page with ionic-react and #ionic-react-router.
The products have different variants, soo I created a optional url parameter to enable smooth sharing.
My route is defined like this:
product: {
component: ProductPage,
background: '/images/dashboard-navigation-productOverview.png',
key: 'PRODUCT',
path: '/product/:id/:variantId?'
},
My ProductPage Component looks like this:
import React, { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import { IonPage, IonContent } from '#ionic/react';
....
const ProductPage = ({match}) => {
const [variants, setVariants] = useState([]);
const [source, setSource] = useState(null);
const [variant, setVariant] = useState(null);
useEffect(() => {
(async () => {
const response = await productService.getProduct(parseInt(match.params.id, 10))
setSource(response);
})();
}, [match.params.id]);
useEffect(() => {
const variants = productHelpers.allVariantsFromSource(source);
if (match.params.variantId) {
const variant = productHelpers.getProductVariationById(variants, parseInt(match.params.variantId, 10));
setVariant(variant || variants[0]);
} else {
// 0 is always main detail
setVariant(variants[0]);
}
setVariants(variants);
}, [source, match.params.variantId]);
return <IonPage>
<Toolbar title={(source) ? source.name : ''}/>
<IonContent>
<Product source={source} variant={variant} variants={variants}/>
</IonContent>
</IonPage>
}
export default ProductPage;
And somewhere in product I want to change the variation with replacing the url.
So the user can use the back button, to get back where he comes from (mostly product list).
import React, {useContext} from "react";
import {IonButton, NavContext} from '#ionic/react';
const ProductVariant = ({source, newVariant}) => {
const {navigate} = useContext(NavContext);
return (
<IonButton
onClick={() => navigate(`/product/${source.id}/${newVariant.id}`, 'none', 'replace')}>{newVariant.name}</IonButton>
);
};
My Problem
The page URL is updating like I want to, The back function is working too.
But the page transition is still happening.
What i'm doing wrong??

How to implement multiple API in one component

i stuck in a project where i have to implement JSON Place Holder Post API and JSON Place Holder Comment API both API in a particular component.Actually my task is build a project like a facebook post component where user can post and comment. I implemented Post API successfully but i couldn't find any solution to use comment API. I did all thing but it's not show in my Home component.
How can i implement comment api in my home component
my console said it present but i couldn't show this
This is Home.js File
import React, { useEffect, useState } from 'react';
import Post from '../Post/Post';
import Comment from '../Comment/Comment';
import './Home.css';
const Home = () => {
const [post,setPost] = useState([]);
const [comment,setComment] = useState([]);
useEffect(()=>{
fetch('https://jsonplaceholder.typicode.com/posts')
.then(res=>res.json())
.then(data=>setPost(data))
},[])
useEffect(()=>{
fetch('https://jsonplaceholder.typicode.com/comments')
.then(res=>res.json())
.then(data=>setComment(data))
},[])
return (
<div>
<div>
{
post.map(post=><Post post={post}></Post>)
}
</div>
<div className="main-body">
{
comment.map(comment=><Comment comment={comment}></Comment>)
}
</div>
</div>
);
};
export default Home;
This comment.js File
import React from 'react';
const Comment = (props) => {
const {name,email} = props.comment.name;
console.log(props.comment);
return (
<div>
{name}
{email}
</div>
);
};
export default Comment;
This is post.js File
import React from 'react';
import './Post.css';
const Post = (props) => {
const {title,body} = props.post;
return (
<div className="body-style">
<h1 className="name">{title}</h1>
<p>{body}</p>
</div>
);
};
export default Post;
Please help me I need solution
The structure is incorrect, in order to do that, comment should be children of post, and home will pass data to the post. Since you fetch data from 2 difference API, you need to combined it into 1 source and pass that down.
Home.js
import React, { useEffect, useState } from 'react';
import Post from '../Post/Post';
import './Home.css';
const Home = () => {
const [post,setPost] = useState([]);
const [comment,setComment] = useState([]);
const [ info, setInfo ] = useState([]);
useEffect(()=>{
fetch('https://jsonplaceholder.typicode.com/posts')
.then(res=>res.json())
.then(data=>setPost(data))
},[])
useEffect(()=>{
fetch('https://jsonplaceholder.typicode.com/comments')
.then(res=>res.json())
.then(data=>setComment(data))
},[])
//Function to combine post and comment base on ID
const merge = (post, comment) => {
const temp = [];
post.forEach((x) => {
comment.forEach((y) => {
if (x.id === y.id) {
let cName = y.name;
let cEmail = y.email;
let cBody = y.body;
temp.push({ ...x, cName, cEmail, cBody });
}
});
});
return temp;
};
useEffect(
() => {
setInfo(merge(post, comment));
console.log(info);
},
[ post, comment ]
);
return (
<div>
{info.map((each) => <Post key={each.id} data={each} />)}
</div>
);
};
export default Home;
Post.js
import React from 'react';
import Comment from './Comment';
const Post = (props) => {
const { title, body, cEmail, cName } = props.data;
return (
<div className="body-style">
<h1 className="name">{title}</h1>
<p>{body}</p>
<Comment email={cEmail} name={cName} />
</div>
);
};
export default Post;
Comment.js
import React from 'react';
const Comment = ({ name, email }) => {
return (
<div>
{name}
{email}
</div>
);
};
export default Comment;

Call useQuery after retrieving router query object (NextJS with GraphQL)

I am retrieving the query param in NextJS using:
const qry_flightNumber = Number(router.query.flightNumber);
Then i want to send a request to my GraphQL server by doing this:
PAGE: LaunchDetails.js
import React, { useEffect, useState } from "react";
import classNames from "classnames";
import gql from "graphql-tag";
import { useQuery } from "#apollo/react-hooks";
import PropTypes from "prop-types";
const LAUNCH_QUERY = gql`
query LaunchQuery($flight_number: Int!) {
launch(flight_number: $flight_number) {
flight_number
mission_name
launch_year
launch_success
launch_date_local
rocket {
rocket_id
rocket_name
rocket_type
}
}
}
`;
export default function LaunchDetails({ flightNum }) {
const { loading, error, data } = useQuery(LAUNCH_QUERY, {
variables: { flight_number: flightNum },
});
if (loading) return <p>Loading...</p>;
if (error) return <p>Error</p>;
console.log("data.launch: ", data.launch);
const flightNumber = data.launch.flight_number;
const launchDate = data.launch.launch_date_local;
const launchSuccess = data.launch.launch_success;
const launchYear = data.launch.launch_year;
const missionName = data.launch.mission_name;
const { rocket } = data.launch;
return (
<div>
<h1 className="display-4 my-3">
<span className="text-dark">Mission: {missionName}</span>
</h1>
<h2 className="mb-3">Launch details</h2>
<ul className="list-group">
<li className="list-group-item">Flight number: {flightNumber}</li>
<li className="list-group-item">Launch year: {launchYear}</li>
<li className="list-group-item">
Launch successful:{" "}
<span
className={classNames({
"text-success": launchSuccess,
"text-danger": launchSuccess === false,
})}
>
{launchSuccess ? "yes" : "no"}
</span>
</li>
</ul>
<h4 className="my-3">Rocket details:</h4>
<ul className="list-group">
<li className="list-group-item">Rocket ID: {rocket.rocket_id}</li>
<li className="list-group-item">Rocket name: {rocket.rocket_name}</li>
<li className="list-group-item">Rocket type: {rocket.rocket_type}</li>
</ul>
<hr />
</div>
);
}
LaunchDetails.propTypes = {
flightNum: PropTypes.number.isRequired,
};
Dynamic PAGE containing the component ([flight_number].js):
import { ApolloProvider } from "#apollo/react-hooks";
import React from "react";
import Link from "next/link";
import { useRouter } from "next/router";
import APOLLO_CLIENT from "../../graphql/config";
import LaunchDetails from "../../components/launches/LaunchDetails";
export default function Home() {
const router = useRouter();
const flightNum = Number(router.query.flightNumber);
return (
<>
{/* <Head>
<title>SpaceX launch</title>
</Head> */}
<ApolloProvider client={APOLLO_CLIENT}>
<div className="container">
<h1 className="title">Apollo launch details</h1>
<LaunchDetails flightNum={flightNum} />
<Link href="/">
<a className="btn btn-secondary">Back</a>
</Link>
</div>
</ApolloProvider>
</>
);
}
The issue is have is that on first page load, the GraphQL query executes with flight_number being null. So i end up with this warning in console:
[GraphQL error]: Message: Variable "$flight_number" of non-null type "Int!" must not be null., Location: [object Object], Path: undefined
I have tried using an IF statement to make sure that flight_number is !NaN before running the query however react complains about the order of the hooks being called.
Obviously after the component has fully loaded, the GraphQl variable becomes defined and then executes correctly however I will still be getting the console warning.
Console warning screenshot:
What are my options to stop the console warning?
Thank you.
I have got an answer to this now. You can pass a skip parameter to the useQuery to only exec the query if the variable is defined or not NaN:
const { loading, error, data } = useQuery(LAUNCH_QUERY, {
variables: { flight_number: flightNum },
skip: Number.isNaN(flightNum),
});

Understanding React.JS JSON feed and how to parse

I've got the following code which is looping through an JSON file from an API and loops through some posts.
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
//https://alligator.io/react/axios-react/
import axios from 'axios';
export default class PostList extends React.Component {
state = {
posts: []
}
componentDidMount() {
axios.get(`https://jsonplaceholder.typicode.com/users`)
.then(res => {
const posts = res.data;
this.setState({ posts });
})
}
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<p className="App-intro">
Pulls in post slugs from Domain
</p>
<ul>
{ this.state.posts.map(post => <li>{post.name} - {post.username} </li>)}
</ul>
</div>
)
}
}
This works fine, and gets the information which was needed.
Now, in my test JSON file, the format is as follows:
https://jsonplaceholder.typicode.com/users
But in my actual JSON file from WordPress Rest API, we have another item, named core_layout:
JSON image
My issue is, trying to use the same code such as {post.name}does not get the information needed such as core_layout->image->name.
Is there an easy way around this?
Thanks all!
EDIT:
Tried the answers below, but still no luck, get the error TypeError: Cannot read property 'map' of undefined:
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
//https://alligator.io/react/axios-react/
import axios from 'axios';
export default class PostList extends React.Component {
state = {
posts: [],
coreLayout: {}
}
componentDidMount() {
axios.get(`https://jsonplaceholder.typicode.com/users`)
.then(res => {
// const posts = res.data;
//this.setState({ posts });
const { posts, core_layout: coreLayout } = res.data;
this.setState({ posts, coreLayout });
})
}
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<p className="App-intro">
Pulls in post slugs from domain
</p>
<ul>
{ this.state.posts.map(post => <li>{post.name} - {post.core_layout.image.name}</li>)}
</ul>
</div>
)
}
}
EDIT 2:
Tried the below: This gets the title, but again, not the actual corelayout I need.
import React, { Component } from 'react';
class App extends Component {
constructor() {
super();
this.state = {
movies: []
}
}
componentDidMount() {
let dataURL = "http://zinsseruk.com/wp-json/wp/v2/posts?per_page=1";
fetch(dataURL)
.then(res => res.json())
.then(res => {
this.setState({
movies: res
})
})
}
render() {
let movies = this.state.movies.map((movie, index) => {
return <div key={index}>
<p><strong>Title:</strong> {movie.title.rendered}</p>
<p><strong>Title:</strong> {movie.core_layout.acf_fc_layout}</p>
</div>
});
return (
<div>
<h2>Star Wars Movies</h2>
{movies}
</div>
)
}
}
export default App;
Replace const posts = res.data; with const posts = res.data.core_layout;. Then you'll get an array similar to what you have in your test file.
I think you need to understand the JSON structure you receive from the API. Where is located core_layout property? Inside each post property as a children?
So in the posts loop you can use post.core_layout.image.name for image name, for example (and so on with other properties).
If core_property is at the root of the data you receive, you can load it inside your state like so:
state = {
posts: [],
coreLayout: {}
}
componentDidMount() {
axios.get(`https://jsonplaceholder.typicode.com/users`)
.then(res => {
// This is equivalent of doing
// const posts = res.data.posts
// const coreLayout = res.data.core_layout
const { posts, core_layout: coreLayout } = res.data;
this.setState({ posts, coreLayout });
})
}
Then use it in your code by using local component state:
render() {
...
// For example image name:
console.log('image name', this.state.coreLayout.image.name)
...
}