Im trying to simply have a shared variable between my pages in my Next.Js application.. My _app.js below contains the following..
import { useState } from 'react';
const CustomApp = ({ Component, pageProps }) => {
// Variables
const [testVariable, setTestVariable] = useState(0)
// globalFunctions
const setTestVariable = (newValue) => setLocalVariable(newValue);
return (
<Component
{...pageProps}
// Export Variables
testVariable={testVariable}
// Export Functions
setTestVariable={setTestVariable}
/>
);
}
export default CustomApp
I have two pages... Both are the same except one is called index.js and exports Home, the other is called about.js and exports About...
import { useState, useEffect } from 'react'
import 'bulma/css/bulma.css'
import styles from '../styles/Home.module.css'
const Home = ({ testVariable, setTestVariable, }) => {
useEffect(() => {
})
return (
<div id={styles.outerDiv}>
<Head>
<title>My Next.Js Page</title>
<meta name="description" content="A Next.js application" />
</Head>
<div id={styles.navBar}>
<a href="/" id={styles.navLink}>
<h3>Home</h3>
</a>
<a href="/about.js" id={styles.navLink}>
<h3>About</h3>
</a>
</div>
<div id={styles.content} className="content">
<br/>
<h2>Test Variable: {testVariable}</h2>
<button id={styles.incrementButton} onClick={setTestVariable(1)}>Set Test Variable to 1</button>
</div>
</div>
)
}
export default Home
When I tap the button the variable on my page changes to 1, however when I switch pages the variable goes back to 0. I also receive no errors of any sort. All feedback is greatly appreciated! Thanks for your time.
The variable goes back to 0 because you are using a tags wich "reloads" the page
To navigate you should use the Link component that is built in next.
This Link component prevents the default behavior of reload the page and you can keep your state while navigate on the page
Related
Hi im trying to get a loading page to show while website is taking the time to load. as it quite a large website I thought a loading screen would provide the best possible user experience however I cannot seem to figure out how to get it to work on nextjs 13. I have created a simple functional component that says loading... and have imported it directly into my layout.jsx folder.
I am using the app directory method which is quite new and im also new at nextjs so im a little lost ^^
I imagine I might need to set state at some point but I cant seem to figure out when and where to do it
any advice would be great.
thanks
import "./globals.css";
import React, { useState, useEffect } from "react";
import Loading from "../components/loading/loading";
const Layout = ({ children, dataLoaded }) => {
const [loading, setLoading] = useState(true);
useEffect(() => {
if (dataLoaded) {
setLoading(false);
}
}, [dataLoaded]);
return (
<body className="app {oswald.className}">
{loading && <Loading />}
{children}
</body>
);
};
export default Layout;
.
.
.
Attempt 1 -
After following one of the answers below it does not seem like my loading page is showing up at all. and no errors showing up.
my layout is as follows
layout.jsx
import "./globals.css";
import { Suspense } from "react";
import Loading from "../components/loading/loading";
export default function RootLayout({ children }) {
return (
<html lang="en">
<head />
<body>
<Suspense fallback={<Loading />}>{children}</Suspense>
</body>
</html>
);
}
LoadingPage.js
const LoadingPage = () => {
return (
<div className="loading w-screen h-screen bg-red-100">
<p>Loading...</p>
</div>
);
};
export default LoadingPage;
Loading.js
import LoadingPage from "#/components/loading/loading";
export default function Loading() {
return <LoadingPage />;
}
In NextJS 13, there's actually a default way to handle loading states within pages. You can declare a loading.tsx file in your /app directory, with this content:
export default function Loading() {
return <Loading />
}
Then, inside your Layout, you can wrap your page with a Suspense tag, like this:
<Layout>
<Navbar>
...
<Suspense fallback={<Loading/>}>
<Page/>
</Suspense>
</Layout>
Your loading state will be automatically handled upon navigation.
I'm working on a project in NextJS for the first time, and I'm wondering what the right way to handle dynamic routing is.
I have a http://localhost:3000/trips route which displays a page with list of cards, each of which represent a "trip":
When I tap on one of these cards, I want to navigate to a dynamic page for that route such as http://localhost:3000/trips/0b68a50a-8377-4720-94b4-fabdabc12da1
This is my folder structure:
As you can see, I already have the dynamic routes set up and it is working.
TripCard is the card component. TripComponent is a grid of TripCards. trips/index.tsx contains the TripsComponent (and other UI).
Currently I'm handling the dynamic route in TripCard as:
import { Trip } from './Models'
import { useRouter } from 'next/router'
const TripCard = ({ trip }: { trip: Trip }) => {
const router = useRouter()
return (
<div className="card bg-base-100 shadow-xl hover:bg-gray-100 active:bg-gray-300">
<div className="card-body" onClick={() => router.push('/trips/' + trip.id)}>
<h2 className="card-title">{trip.name}</h2>
<p>This is a trip!</p>
</div>
</div>
)
}
export default TripCard
And the dynamic page [tripId].tsx looks like:
import { NextPage } from 'next'
import { useRouter } from 'next/router'
const TripPage: NextPage = () => {
const router = useRouter()
const tripId = router.query.tripId
return (
<div>
<h1>This is {tripId}</h1>
</div>
)
}
export default TripPage
And TripsComponent.tsx:
import { Trip } from './Models'
import TripCard from './TripCard'
const TripsComponent = ({ trips }: { trips: Trip[] }) => {
return (
<div>
<div className="grid grid-cols-4 gap-4">
{trips.map((trip: Trip) => (
<div>
<TripCard trip={trip}></TripCard>
</div>
))}
</div>
</div>
)
}
export default TripsComponent
And trips/index.tsx:
import axios from 'axios'
import { GetStaticProps, InferGetStaticPropsType, NextPage } from 'next'
import { Trip } from '../../components/Models'
import TripsComponent from '../../components/TripsComponent'
const TripsPage: NextPage = (props: InferGetStaticPropsType<typeof getStaticProps>) => {
return (
<div className="m-9">
<h1 className="mt-9 text-3xl font-bold text-slate-800">Your Trips</h1>
<div className="justify-end">
<button className="btn btn-primary">Add Trip</button>
</div>
<div className="divider"></div>
<TripsComponent trips={props.data} />
</div>
)
}
export const getStaticProps: GetStaticProps = async () => {
// fetches data and passes to props
}
export default TripsPage
I guess my question is, what is the proper way to do routing like this where I have cards, and each card will go to a dynamic URL with an associated page? In TripCard I have a hardcoded router.push:
<div className="card-body" onClick={() => router.push('/trips/' + trip.id)}>
But that doesn't seem like the right way to handle this. For example, what if I want to use TripCard in another view and go to another route?
What's the best way to structure code that performs this function in NextJS?
Maybe you want to pass the url as props and use NextJs <Link/>:
import { Trip } from './Models'
import { useRouter } from 'next/router'
import Link from 'next/link'
const TripCard = ({ trip, url }: { trip: Trip, url: string }) => {
const router = useRouter()
return (
<div className="card bg-base-100 shadow-xl hover:bg-gray-100 active:bg-gray-300">
<Link href={url} passHref>
<div className="card-body">
<h2 className="card-title">{trip.name}</h2>
<p>This is a trip!</p>
</div>
</Link>
</div>
)
}
export default TripCard
And then use the component like this:
<TripCard trip={trip} href={'/trips/' + trip.id}></TripCard>
Hope this help.
For dynamic routes, you will have to use getStaticPaths and getStaticProps to fetch the paths before and generate all the paths. When you export getStaticPaths from the page Nextjs will pre-render all the paths specified by getStaticPaths.
getStaicPaths has to return two things paths and fallback. paths property will have to be an array of params. And fallback means should Nextjs look for pages and pre-render if not pre-rendered before. Suppose after publishing the site you created a new card. So, If the fallback is true NextJs will look for the card in the database and pre-render then store it in the file system. If fallback is false it will show 404 not found.
Also Instead of using router.push use Link component.
https://nextjs.org/docs/api-reference/data-fetching/get-static-paths
The routing you have implemented is correct only. Maybe you can try like this
For trips, you can navigate to /trips and for each trip /trip/<trip id>
If you want to make the trip URL dynamic then you can pass the URL itself to TripCard component.
url will be <route name>/<trip id>
<TripCard trip={trip} url={url}></TripCard>
I am new to nextjs and webdev. I been following a couple of tutorials but I still have a doubt.
Lets say I have this page:
// /pages/test/load.js
import Link from 'next/link'
import Layout from '../../components/layout'
import { useRouter } from "next/router";
export default function TestLoad() {
const router = useRouter();
const query = router.query;
console.log(query.info)
// I don't want to show any of this code here, or the return in case queri.info != true.
if (query.info == 'true') {
console.log('TRUE RETURN')
return (
<Layout>
<h1>First Post</h1>
<h2>
<Link href="/">
<a>Back to home</a>
</Link>
</h2>
<p>Some hidden content that I don't want to show to all the users.</p>
<p>Blah</p>
// Images and more stuff
</Layout>
)
} else {
return (
<>
<h1>Nothing to show</h1>
<Link href="/">
<a>Back to home</a>
</Link>
</>
)
}
}
If I deploy this code with Vercel for example, and try access to http://<some-url>/test/load?info=false is the code/info for query.info == 'true' available?
Of course in this particular case anyone can just try to access to http://<some-url>/test/load?info=true and view the content.
My idea is then try to wrap up the true/false logic into getStaticProps.
My ultimate idea is to render a different html code depending on the props passed by getStaticProps.
Thanks!
I'm trying to learn Next-JS, and I'm making a small, experimental project to familiarize myself. However, something seems to be going wrong with the Link tag. It does redirect to the friends page specified, but for some reason, the page content remains the same as it is on home. And clicking the test link while on this page, it attempts to redirect not to "#", but to "friends#".
Is there something I'm not understanding here? Any help would be appreciated. Here is my conde:
index.tsx:
import Link from 'next/link';
import styles from '../styles/Home.module.css'
const HomePage = () => {
// const handleClick = (e: Event) => {
// e.preventDefault()
// router.push('./friends')
// alert(router)
return (
<div className={styles.div}>
<h1 className={styles.h1}>WELCOME TO HOME PAGE</h1>
<ul className={styles.ul}>
<li className={styles.li}>
<Link href='/friends'>
<a>FRIENDS</a>
</Link>
</li>
<li className={styles.li}>
<Link href="#">
<a>TEST</a>
</Link>
</li>
</ul>
</div>
)
}
export default HomePage
friends.tsx:
import Link from 'next/link'
const Friends = () => {
return (
<div>
<h1>WELCOME TO FRIENDS</h1>
<Link href="/">
RETURN TO HOME
</Link>
</div>
)
}
export default Friends;
_app.tsx:
import '../styles/globals.css'
import type { AppProps } from 'next/app'
import HomePage from '../pages/index'
function MyApp({ Component, pageProps }: AppProps) {
return <HomePage />
}
export default MyApp
Screentshots of what I'm seeing are listed below. Note the URLs.
Home page
Friends page
After clicking the Test link, for which the href is currently "#"
You're seeing the same page on all links is because you're always displaying the same component, which is <Homepage />. Instead, you need to render the component with pageProps to display the correct page according to the url.
The updated code of the _App component should be something like, where you need to display the Component available through the props.
import '../styles/globals.css'
import type { AppProps } from 'next/app'
function MyApp({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />
}
export default MyApp
Please also take a look at the docs of the Next.js regarding the custom _app, to see available options/features out of the box.
From docs: The Component prop is the active page, so whenever you navigate between routes, Component will change to the new page. Therefore, any props you send to Component will be received by the page.
pageProps is an object with the initial props that were preloaded for your page by one of our data fetching methods, otherwise it's an empty object.
I have created a next js project with normal javaScript.This is my 404 page
404.js
import { useEffect } from "react";
import { useRouter } from "next/router";
import Link from "next/link";
export default function NotFound() {
const router = useRouter();
useEffect(() => {
setTimeout(() => {
// router.go(1)
router.push("/");
}, 3000);
}, []);
return (
<div className="not-found">
<h1>Oooops!!!</h1>
<p>
Go back to home page
<Link href="/">
<a>Home page</a>
</Link>
</p>
</div>
);
}
Then I created a seperate type script based next js project.
404.tsx
// import type { NextPage } from 'next'
import Link from "next/link";
const NotFound = () => {
return (
<div>
<h2>Oh no!</h2>
<p>There is not much left here for you</p>
{/* <Link href="/">
<a >Visit our home page</a>
</Link> */}
</div>
);
};
export default NotFound;
This is what I get in the typescript project.
What is wrong in the 404.tsx file?
It says that client_dev_noop_js module loading failed. There is nothing with 404.tsx, however, it is better to name _error.js and _error.tsx