I'm trying to implement dynamic routing on a Gatsby site - I'm fetching launch data from the SpaceXAPI and creating a new page if a launch contains details. These details pages load correctly when you click on the 'View Details' link to view them from the homepage. When you access the page directly by its url, the page information is not found, resulting in a 404.
Why won't pages with this route load on their own? I'm also looking into ways to persist the state that I'm currently passing in to <Link>.
Repository: https://github.com/nikkipeel/gatsby-spacex
I'm not using <Router> or the createPages API...this is my project structure:
Accessing state through location on the page:
[name].js:
import * as React from 'react'
import moment from 'moment'
import Seo from '../../components/seo'
import ScrollToTop from '../../components/scrollToTop'
import Footer from '../../components/footer'
import '../../styles/tailwind.css'
const Launch = ({ location, name }) => (
<>
<main className="h-screen w-full bg-gray-900 text-white mx-auto">
<Seo title={name} />
{name && (
<>
<div className="flex flex-col md:w-3/4 lg:w-1/2 p-12 mx-auto text-base" key={name}>
<h1 className="mission-name tracking-wide font-bold text-2xl my-4">{name}</h1>
<strong className="tracking-wide text-xl my-2">Flight # {location.state.flight_number}</strong>
<div className="flex items-center my-2">
<strong className="text-xl mr-2">Mission: </strong>
<p className="text-base">{location.state.name}</p>
</div>
<div className="flex items-center my-2">
<strong className="text-xl mr-2">Launch Date: </strong>
<p>{moment(location.state.date_local).format('dddd, MMMM Do YYYY, h:mm:ss a')}</p>
</div>
{location.state.details && <p className="my-2">{location.state.details}</p>}
<a
href={location.state.links.wikipedia}
className="my-2 font-bold font-mono bg-clip-text text-transparent bg-gradient-to-t from-blue-500 via-blue-400 to-blue-300 transition duration-500 ease-in-out hover:text-blue-300 hover:underline pr-8"
>
Learn More
</a>
{location.state.links.video_link && (
<a
href={location.statelinks.video_link}
className="my-2 font-bold font-mono bg-clip-text text-transparent bg-gradient-to-t from-blue-500 via-blue-400 to-blue-300 transition duration-500 ease-in-out hover:text-blue-300 hover:underline p-2"
>
View Launch
</a>
)}
</div>
</>
)}
</main>
<ScrollToTop showBelow={250}></ScrollToTop>
<Footer></Footer>
</>
)
export default Launch
Setting state in <Link> in pastLaunches.js:
<Link
to={`/launches/${name}`}
state={{
name: name,
flight_number: flight_number,
date_local: date_local,
links: links,
rocket: rocket,
details: details
}}
className="mt-4 font-bold font-mono bg-clip-text text-transparent bg-gradient-to-t from-blue-500 via-blue-400 to-blue-300 transition duration-500 ease-in-out hover:text-blue-300 hover:underline w-48"
>
View Details
</Link>
Gatsby collection routes: https://www.gatsbyjs.com/docs/reference/routing/file-system-route-api/
Gatsby example client-only paths: https://github.com/gatsbyjs/gatsby/tree/master/examples/client-only-paths
Netlify issue with Gatsby and 404 pages: https://answers.netlify.com/t/gatsby-4-runtime-importmoduleerror-on-404-pages/46608
Related
I'm trying to get an array from a JSON object and then, map it in order to get the data.
Here is the data returned from an API:
{
project: [
{
_createdAt: '2022-12-15T16:45:57Z',
_id: 'cb39338d-4e6d-4c28-9a79-499afca392e6',
_rev: '974wCYB6EQ3xW9LGNZhQvU',
_type: 'project',
_updatedAt: '2022-12-27T04:55:54Z',
image: [Object],
linkToBuild: 'https://github.com/Arotiana137-51/charitty_to_portfolio_jsp',
summary: "This is a project I've done for learning purpose at the University. I've learned the basics of web programing with Java Server Pages ,Servelet ,....", technologies: [Array],
title: 'Charity '
}
]
}
And I wish to map this array in order to get elements from it inside this JSX element :
import React from "react";
import {motion} from 'framer-motion';
import { Project } from "../typing";
import { urlFor } from "../sanity";
type Props = {
projects:Project[];
};
function Projects({projects}: Props) {
console.log(projects);
return (
<motion.div
initial={{opacity:0}}
whileInView={{opacity:1}}
transition={{duration:1.5}}
className="h-screen relative flex overflow-hidden flex-col text-left md:flex-row max-w-full justify-evenly mx-auto items-center z-0">
<h3 className="absolute top-24 uppercase tracking-widest text-teal-400 text-2xl ">
Projects
</h3>
<div className="relative w-full flex overflow-x-scroll overflow-y-hidden snap-x snap-mandatory z-20">
{/*----------- HERE I TRY TO ACCESS THE ARRAY AND MAP IT DIRECTLY, LIKE IN JS-----------------------------------*/}
{ projects.project.map((project,i) => (
<div className="w-screen flex-shrink-0 snap-center flex flex-col space-y-5 items-center justify-center p-20 md:p-44 h-screen">
<motion.img
initial ={{
y: -300,
opacity:0
}}
transition={{duration: 1.2}}
whileInView = {{opacity:1 , y:0 }}
viewport={{ once: true}}
src={urlFor(project.image).url()}
alt="#"/>
<div className=" space-y-10 px-0 md:px-10 max-w-6xl ">
<h4 className="text-4xl font-semibold text-center">
Case study {i+1} of{projects.length}: <span className="underline decoration-teal-700"> {project?.title}</span>
</h4>
<div className="flex items-center space-x-2 justify-center">
{
project?.technologies.map((technology)=>(
<img
className="h-10 w-10"
key={technology._id}
src={urlFor(technology?.image).url()}
alt=""
/>
))
}
</div>
<p>{project?.summary}</p>
</div>
</div>
))}
</div>
<div className="w-full absolute top-[30%] bg-teal-800 left-0 h-[500px] -skew-y-12">
</div>
</motion.div>
);
}
export default Projects;
This normally works on js but my compiler return:
Server Error
TypeError: Cannot read properties of undefined (reading 'map')
because it still considers the prop as an object, even if I try to access the array at the code above, how can i solve it?
You are trying to do project?.technologies.map, but as i see at the JSON above , there is simply no "technologies" key.
I have been looking at this piece of code for over 2 days now, and i have not been able to locate my Hydration error. It is driving me crazy. Could some one maybe take a look at it for me? Are there any tips and tricks to spot these kind of errors more quickly, would love to know!
I'am using nextjs and using axios for the get resquest
These are the errors:
Error: Hydration failed because the initial UI does not match what was rendered on the server.
Error: There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.
react-dom.development.js?ac89:19849 Uncaught Error: There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.
export async function getStaticProps() {
try {
const res = await axios.get('https://open.data.amsterdam.nl/Festivals.json')
const events = res.data;
return {
props: {
events: events.slice(0, 10)
}
}
} catch (error) {
console.log(error)
}
}
function EventsCards({events}) {
return (
<div>
<a id="pressable-card max-w-md">
<div id="featured-event-container" className="bg-black rounded-md bg-opacity-20 bg-blur-sm max-w-xs shadow-lg">
<div id="event-banner">
<img className="max-w-lg w-full h-full" src={events.media[0].url }/>
</div>
<div className="text-white pl-2">
<h1 className="text-lg font-medium text-transparent bg-clip-text bg-gradient-to-r from-purple-400 to-pink-600">{events.title}</h1>
<a className="text-sm uppercase">{events.title}</a>
<a className="text-xs text-">Friday 20 Jan | 13:00 - 02:00</a>
</div>
<div className="py-2 px-2">
<p className="text-slate-200 font-normal border-[1px] py-[2px] px-[4px] rounded-lg border-slate-400 w-8 text-[8px]">Techno</p>
</div>
</div>
</a>
</div>
)
}
function Events({events}) {
return (
<div className="bg-gradient-to-t from-gray-500 to-gray-900 h-full bg-blur-sm pt-2">
<div className="max-w-6xl mx-auto">
<div className="px-8 ">
<div className="flex">
<h1 className="text-white font-regular opacity-100 tracking-wider sm:text-xl md:text-2xl">Featured events in Amsterdam</h1>
<div className="pl-2 my-auto">
<img className="rounded-full w-8 h-8 md:w-6 md:h-6 border-gray-400" src="https://www.fotw.info/images/n/nl.gif"></img>
</div>
</div>
<ul className="grid grid-cols-1 md:grid-cols-2 pt-4 md:w-full">
<div id="featured-wrapper" className="bg-black rounded-md bg-opacity-20 bg-blur-sm max-w-xs shadow-lg">
<a id="pressable-card max-w-md">
<div id="featured-event-container">
<div id="event-banner">
<img className="max-w-lg max-h-lg w-full h-full" src='https://d1as2iufift1z3.cloudfront.net/rails/active_storage/blobs/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBaWpqIiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--696c8f363a91d0501e8ae333fc9d42e5fd9c225f/ERT_HOLLAND_SIGNUP_banner%20(1).jpg?proxy=true'></img>
</div>
<div className="text-white pl-2">
<h1 className="text-lg font-medium text-transparent bg-clip-text bg-gradient-to-r from-purple-400 to-pink-600">El Row Town 2022 - Holland</h1>
<a className="text-sm uppercase">{events.title}</a>
<a className="text-xs text-">Friday 1 Jan | 11:00 - 04:00</a>
</div>
<div className="py-2 px-2">
<a className="text-slate-200 font-normal border-[1px] py-[2px] px-[4px] rounded-lg border-slate-400 w-8 text-[8px]">Techno</a>
</div>
</div>
</a>
</div>
<div className="text-red-400"><h1>test</h1></div>
</ul>
</div>
{/* Amsterdam Events */}
<div className="flex justify-center py-8">
<button className="text-[8px] uppercase font-medium rounded-md py-[8px] px-2 bg-white">see events in Amsterdam</button>
</div>
{/* All Events */}
<div className="mx-auto max-w-6xl w-full">
<h1 className="px-8 text-white font-regular tracking-wider text-xl md:text-2xl">Amsterdam</h1>
</div>
<div className="max-auto max-w-6xl">
<div className="grid grid-cols-1 md:grid-cols-3 pt-4 md:w-full w-full px-8 gap-4">
{events.map((event) => (
<EventsCards key={event.id} events={event} />
))}
</div>
</div>
</div>
</div>
)
}
export default Events;```
There are a couple of issues with your code that are causing issues:
Invalid markup (anchor tags inside other anchor tags, ul tags without li children).
You are passing the prop events to your <EventCard /> component (it should have a name that is different from the events array retrieved server-side)
You are using a event.id for your key prop when none exists (it should be event.trcid).
Here's a basic working version of your components:
export default function Events({ events }) {
return (
<>
{events.map((event) => (
<EventsCards key={event.trcid} event={event} />
))}
</>
);
}
function EventsCards({ event }) {
return <div>{event.title}</div>;
}
export async function getStaticProps() {
try {
const res = await axios.get(
'https://open.data.amsterdam.nl/Festivals.json'
);
const events = res.data;
return {
props: {
events,
},
};
} catch (error) {
console.log(error);
}
}
More often, it's best to start by getting the data on the page and then add in your additional content and styles.
It happens because you make some changes on the server side and save them before the Fast-Refresh completes hence causing a hydration error. You can manually reload the page after completing saving the changes or wait for Fast-Refresh to complete and then save your codes.
I am quite new to react and am trying to create a sports fixture application where when you click on one of the fixtures in the list it takes you to a new page with more things you can do for that fixture.
On my home page I render the list of popular fixtures which I have set in a JSON called popular.json. I have this coded so if I add or remove a fixture from popular.json then this will automatically be rendered by having my component set up as below
import fixtures from './variables/popular.json'
export const setFixture = (id, home, homeLogo, away, awayLogo, date, time, venue) => {
const match = { id: id, teamA: home, teamALogo: homeLogo, teamB: away, teamBLogo: awayLogo, date: date, time: time, stadium: venue }
}
export default function Example() {
return (
<div >
<div className="max-w-4xl mx-auto px-4 py-1 sm:px-6 sm:pt-20 sm:pb-24 lg:max-w-7xl lg:pt-10 lg:px-8">
<h2 className="text-4xl font-bold text-white tracking-tight">
Popular
</h2>
<ul
time="list"
className="grid grid-cols-1 py-10 gap-6 sm:grid-cols-2 lg:grid-cols-3"
>
{fixtures.map((fixture) => (
<li key={fixture.id} className="col-span-1 rounded-lg bg-white bg-opacity-70 hover:bg-gray-100 shadow">
<a href="/game" onClick={setFixture(fixture.home,fixture.homeLogo,fixture.away,fixture.awayLogo,fixture.date,fixture.time,fixture.venue)}>
<div>
<div className="-mt-px flex">
<div className="flex w-0 flex-1">
<div className="mx-auto py-5 flex-shrink-0 flex justify-center">
<img
className="h-16 w-16"
src={fixture.homeLogo}
alt="Logo"
/>
</div>
</div>
<div className="w-1"></div>
<div className="-ml-px flex w-0 flex-1">
<div className="mx-auto py-5 flex-shrink-0 flex items-center justify-center">
<img
className="h-16 w-16"
src={fixture.awayLogo}
alt="Logo"
/>
</div>
</div>
</div>
<div className="-mt-px items-center flex">
<div className="flex w-0 flex-1">
<div className="relative -mr-px inline-flex w-0 flex-1 items-center justify-center rounded-bl-lg border border-transparent py-4 text-3xl font-bold text-gray-600 hover:text-purple-600">
<span className="justify-center">{fixture.home}</span>
</div>
</div>
<div className="flex w-1">
<div className="justify-center flex w-0 flex-1">
<span className="text-4xl font-bold text-center text-gray-600 hover:text-purple-600 tracking-tight">
V
</span>
</div>
</div>
<div className="-ml-px flex w-0 flex-1">
<div className="relative inline-flex w-0 flex-1 items-center justify-center rounded-br-lg border border-transparent py-4 text-3xl font-bold text-gray-600 hover:text-purple-600">
<span className="justify-center">{fixture.away}</span>
...
and so on and it looks like this render of fixtures
When you click on one of these games it redirects to the /game page where I want to build add more stuff you can see about each game.
I want to know which game has been selected by the setFixture function which is called onClick of one of the games, and then I want to pass in the match variable to my new component (which is in a different .jsx file) so that I can render the game that has been selected on the new page.
I have tried to import the match variable from this file and the setFixture function in the new component file but cannot set my variables for the teams, date, venue etc. from this import and am just seeing many errors.
Can anyone help me with how this can be done? Recognizing which game has been selected and loading this into another file?
Thank you so much!
The usual approach to problems in React is to make use of Components. A component represents an object, and is provided a set of properties to allow that instance of the object to be represented.
So, even before going to your "next page" think about the Components that you could have on this "page" - each of the Fixtures you are representing can be a Component that takes properties that will help render the teams in that match. This will then lead to less repetition in each of your components - the Example() component will now render (for example) 6 Fixture() components.
Also, React is usually a Single Page Application. Whilst you're getting your basic application working you don't need to consider Routing just yet. Also, pages aren't "loaded"; components are re-rendered when Component properties ("props" for short) are updated. So, in the same page above you could have a Game() component that initially doesn't have any team props sent to it and behaves by not rendering until it has teams set.
You could use something like https://stackblitz.com/ to showcase what you have now, and it'd be easier to show how your code can be simplified.
How to paginate in react using inertia on laravel?
pulling the paginated data:
$contacts = Contact::orderBy('name', 'asc')->paginate(10);
return Inertia::render('Contacts/index', [
'contacts' => $contacts
]);
I know how to render the links in blade ({{ $contacts->links() }}) but is there a way to do it like that on inertia or do I need to make my own component for pagination links?
The easiest way is to create your own component with the links (those are still there)
This is an example in vue, but should be easy to port to react:
<template>
<div>
<div class="flex flex-wrap -mb-1">
<template v-for="(link, key) in links" :key="key">
<div v-if="link.url === null" class="mr-1 mb-1 px-4 py-3 text-sm leading-4 text-gray-400 border rounded"
v-html="link.label" />
<inertia-link v-else
class="mr-1 mb-1 px-4 py-3 text-sm leading-4 border rounded hover:bg-white focus:border-indigo-500 focus:text-indigo-500"
:class="{ 'bg-blue-700 text-white': link.active }" :href="link.url" v-html="link.label" />
</template>
</div>
</div>
</template>
<script>
export default {
props: {
links: Array
},
}
</script>
You can Try This for better result for react :-
import DataTable from "react-data-table-component";
<DataTable
style={{ background: "transparent" }}
title="User"
columns={columns}
data={allData}
defaultSortFieldId={1}
sortIcon={<ArrowUpwardIcon />}
pagination
/>
i have a blog post page that load content via graphql, in the content are scripts tag of charts.
the problem is that when using it does not load the scripts. Only load the scripts if you refresh the browser.
So i added the scripts to helmet after data loaded but they dont run/load .
Is there a way to "refresh" the dom?
import React, { useEffect,useState, Suspense } from "react"
import { Link, graphql } from "gatsby"
import Img from "gatsby-image"
import Layout from "../components/layout"
import EmbedContainer from "react-oembed-container"
import SEO from "../components/seo"
import { Helmet } from "react-helmet"
const PostContentComponent = React.lazy(() => import('../components/PostContentComponent'));
const BlogPost = ({ data }) => {
const [scripts,setScripts] = useState([])
function getScripts () {
// get all script tags from content
const re = /<script\b[^>]*>[\s\S]*?<\/script\b[^>]*>/g
const results = setScripts(data.strapiPost.content.match(re))
return results
}
console.log('scripts', scripts)
useEffect(() => {
getScripts()
// window.instgrm.Embeds.process()
// window.twttr.widgets.load()
}, [data])
return (
<>
<Layout>
<Helmet>
{scripts ? scripts.map((script)=> {
return script
}): null}
</Helmet>
<SEO title={data.strapiPost.title}/>
<section className="posts-container mx-auto all-blog-content my-5 sm:my-20 px-5">
<h3 className="text-1xl sm:text-3xl font-black mb-3">
{data.strapiPost.title}
</h3>
<div className="autor flex flex-wrap items-start">
<div className="autores flex ">
<div className="autorInfo flex items-start">
<h2 className="text-sm tracking-tighter text-gray-900">
By{" "}
{data.strapiPost.users_permissions_users.length === 1 ? (
<>
<Link className="hover:text-black transition duration-300 ease-in-out text-xs mr-1">
{data.strapiPost.users_permissions_users[0].username}
</Link>{" "}
</>
) : data.strapiPost.users_permissions_users.length === 2 ? (
data.strapiPost.users_permissions_users.map((x, index) => (
<>
<Link
className="hover:text-black transition duration-300 ease-in-out text-xs mr-1"
>
{x.name} {x.lastname}{" "}
{index <
data.strapiPost.users_permissions_users.length - 1
? " &"
: ""}
</Link>
</>
))
) : null}
</h2>
</div>
</div>
{/* LOAD CATEGORIES */}
<div className="md:ml-5">
<ul className="flex flex-nowrap relative ">
{data.strapiPost.categories.map(cat => {
return (
<Link
key={cat.name}
className={`bg-gray-200 py-1 px-2 mr-1 rounded-lg text-black text-xs flex-grow `}
>
{cat.name}
</Link>
)
})}
</ul>
</div>
</div>
<span className="text-gray-600 mr-3 text-xs">
Updated at {new Date(data.strapiPost.updated_at).toDateString()}
</span>
<div className="posts-content py-10">
<Img
alt={data.strapiPost.title}
key={data.strapiPost.featured_image.childImageSharp.fluid.src}
imgStyle={{ objectFit: "contain" }}
fluid={data.strapiPost.featured_image.childImageSharp.fluid}
className="mb-10"
/>
<EmbedContainer markup={data.strapiPost.content}>
<div
dangerouslySetInnerHTML={{ __html: unescape(data.strapiPost.content) }}
/>
</EmbedContainer>
</div>
{/* end of all posts */}
{/* AUTHOR CARD */}
<h3 className="text-2xl font-black text-center my-10">
Read More posts by this Author{" "}
</h3>
</section>
<section className="posts-container mx-auto">
<div
className={`grid grid-cols-1 sm:grid-cols-${data.strapiPost.users_permissions_users.length} md:grid-cols-${data.strapiPost.users_permissions_users.length} xl:grid-cols-${data.strapiPost.users_permissions_users.length} gap-4 my-5`}
>
{data.strapiPost.users_permissions_users.map((user, index) => {
return (
<div
key={index}
className="bg-purple-50 flex flex-col items-center justify-center bg-white p-4 shadow rounded-lg"
>
<div className="inline-flex shadow-lg border border-gray-200 rounded-full overflow-hidden h-40 w-40">
{/* <img
src="https://platformable.com/content/images/2020/03/headshot-profile.png"
alt=""
className="h-full w-full my-0"
/> */}
<Img
alt={data.strapiPost.title}
key={index}
fluid={user.image.childImageSharp.fluid}
className="h-full w-full my-0"
/>
</div>
<h2 className="mt-4 font-bold text-xl">
{user.name} {user.lastname}
</h2>
<h6 className="mt-2 text-sm font-medium">{user.position}</h6>
<p className="text-xs text-gray-500 text-center mt-3">
{user.bio}
</p>
</div>
)
})}
</div>
</section>
</Layout>
</>
)
}
export default BlogPost
export const query = graphql`
query MyPost($slug: String!) {
strapiPost(slug: { eq: $slug }) {
categories {
name
}
content
id
title
users_permissions_users {
id
name
lastname
username
image {
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
position
}
updated_at
featured_image {
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
}
}
`
Have you tried something like this:
<Helmet>
{scripts && scripts.map((script)=> <script>{script}</script>)}
</Helmet>
Based on: https://github.com/gatsbyjs/gatsby/issues/6299#issuecomment-402793089
Alternatively, you can use the custom hook approach (useScript).