I am learning Nextjs for the first time, and have experimented by creating a small web app that allows someone to simply register then login. Everything works, except one small issue.
On the page, you can see your status. If you are logged in, it shows your username. If not, it provides a link to the sign in page.
This "Sign In" button is a part of the UserInfoBar component, which is a SSR-component.
The problem is, that when you successfully login, and are redirected to the homepage with router.push('/'), the "Sign In" link is not replaced with your username.
It is only when you refresh the page that your username will show.
I am really at a loss here. The only solution that I can think of is to make UserInfoBar a client component, but then I would have to manually retrieve the session with a fetch call.
Is there not a way to address this from the server side?
src/app/components/UserInfoBar.tsx
import React from 'react'
import Link from 'next/link'
import { getSession } from '../../lib/session'
export default async function UserInfoBar() {
let sessionData = getSession();
console.log('on the server')
console.log(sessionData)
return (
<div className="flex-grow text-right px-2 py-1 text-white">
{sessionData ?
sessionData.username :
<Link href="/signin" className='px-2 py-1 text-white '>Sign In</Link>}
</div>
)
}
src/app/Header.tsx
import React from 'react'
import Link from 'next/link'
import { Suspense } from 'react';
import UserInfoBar from './components/UserInfoBar'
export default function Header() {
return (
<header className='flex justify-center bg-slate-700 mb-7'>
<div className='flex max-width space-x-4 p-4'>
<Link href="/" className='px-2 py-1 text-white '>Home</Link>
<Link href="/decks" className='px-2 py-1 text-white '>Decks</Link>
<Link href="/signup" className='px-2 py-1 text-white '>About</Link>
<Suspense fallback={<p>loading...</p>}>
<UserInfoBar />
</Suspense>
</div>
</header>
)
}
src/app/page.tsx
import React from 'react'
export default function Page() {
return (
<div>
<h2 className="text-4xl font-extrabold text-slate-700">Demo</h2>
<div>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam faucibus erat a gravida ultricies.
</div>
)
}
src/app/lib/session.ts
import { cookies } from 'next/headers';
import jwt from 'jsonwebtoken'
export const getSession = () => {
const nxtCookies = cookies();
if (nxtCookies.has('session')) {
const cookie = nxtCookies.get('session');
let sessionData = jwt.verify(cookie.value, process.env.ACCESS_TOKEN_SECRET, (err, user) => {
if (err) return false;
return user;
});
if (sessionData) return sessionData;
}
return false;
}
While re-reading the Next.js docs, I missed this crucial part:
Invalidating the Cache: The cache can be invalidated using
router.refresh(). For more information, see the API reference. In the
future, mutations will automatically invalidate the cache.
Simply adding router.refresh() before my router.push() call fixed the problem.
Related
I'm trying to connect my app with facebook login. currently i'm using the developer environment under meta developers account.
I have a login component which looks like below -
import Image from "next/image"
import { signIn } from "next-auth/react"
function Login() {
return (
<div className="grid place-items-center">
<Image
src="https://upload.wikimedia.org/wikipedia/commons/4/44/Facebook_Logo.png?20170210095314"
width={300}
height={300}
style={{objectFit:"contain"}}
alt="logo"
/>
<h1
className="p-5 m-5 bg-blue-500 rounded-full text-white text-center cursor-pointer"
onClick={signIn}>Login with Facebook</h1>
</div>
)
}
export default Login
and here is my code from [...nextauth.js]
import NextAuth from "next-auth"
import FacebookProvider from "next-auth/providers/facebook";
export const authOptions = {
providers: [
FacebookProvider({
clientId: process.env.FACEBOOK_CLIENT_ID,
clientSecret: process.env.FACEBOOK_CLIENT_SECRET,
}),
],
}
export default NextAuth(authOptions)
When i click on login with facebook button it throws error
Any help .....
If anyone encountered the same problem below solution works for me.
I made a silly mistake. The Problem was with NEXT_AUTH_URL.
The url was pointing to https://localhost:3000 which is creating the issue.
I have updated url to http://localhost:3000.
And everything working fine.
I am creating a directory of users in Next.js. The users are stored in Supabase. I need for all the users to be displayed in the index.js file, looping through them and showing them on a grid. This is working with getStaticProps, fetching the data and passing it as props profiles.
However, when clicking on each profile, it does redirect me to the [id].js page, but it appends /undefined to the url, rather than the id.
My file tree looks as follows:
pages
people
index.js
[id].js
export default function People({ profiles }) {
return (
<div className="body min-h-[90vh]">
<Head>
<title>People</title>
<link rel="icon" href="/logo" />
</Head>
<div
key={profiles.id}
profiles={profiles}
className="flex flex-col items-center py-16"
>
<div className="grid md:grid-flow-col md:grid-cols-3 xl:grid-cols-4 gap-8 lg:gap-12">
{profiles.map((profile) => (
<Link href={`/people/${profiles.id}`} key={profiles.id}>
<div
profile={profile}
id={profile.id}
className="flex flex-col w-full justify-center items-center p-8 shadow-md hover:shadow-lg"
>
{profile.avatar_url && (
<Image
src={profile.avatar_url}
alt="profile picture"
width={200}
height={200}
className="rounded-full"
object-fit="cover"
/>
)}
<h1 className="text-2xl pt-8 text-center">
{profile.full_name}
</h1>
<p>{profile.skills.skill}</p>
<button className="button w-full">See lessons</button>
</div>
</Link>
))}
</div>
</div>
</div>
);
}
export async function getStaticProps() {
const supabaseAdmin = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL || "",
process.env.SUPABASE_SERVICE_ROLE_KEY || ""
);
const { data } = await supabaseAdmin
.from("profiles")
.select("*, skills(skill)")
.order("id");
console.log(data);
return {
props: {
profiles: data,
},
};
}
Any ideas as to what I am doing wrong are highly appreciated.
Thanks.
I'm working on a react with nextjs project.
I'm using Link to scroll to a specific section on the same page.
Here is one of the components that use Link:
import styles from './section1.module.scss';
import Image from 'next/image';
import Button from '#material-ui/core/Button';
import tought_process from '../../../public/thought_process.png';
import Link from 'next/link';
const Section1 = () => {
return (
<div className={styles.container}>
<div className={styles.left}>
<div className={styles.leftContainer}>
<Link href='#enews'>
<div className={styles.buttonContainer}>
<Button className={styles.buttonstyle1}>Get started</Button>
</div>
</Link>
</div>
</div>
<div className={styles.right}>
<Image
src={tought_process}
className={styles.imageStyle}
alt='how to think about organizing'
layout='responsive'
priority
/>
</div>
</div>
);
};
export default Section1;
And here i mark the element with the id:
<div {...handlers} className={styles.bigBody}>
<NavBar open={menuOpen} toggle={setMenuOpen} scrollY={scrollY} />
<SideMenu open={menuOpen} toggle={setMenuOpen} scrollY={scrollY} />
<div className={styles.sections}>
<Section1 />
<Section2 />
<Section3 id='enews' />
<Section4 />
</div>
Can't figure out what i'm doing wrong.
Multiple clickable elements are wrapping each other. Remove the button and add the anchor element.
<Link href="#enews">
<a>Get started</a>
</Link>
<Link href="#enews">
<a className={styles.buttonContainer}>
<span className={styles.buttonstyle1}>Get started</span>
</a>
</Link>
I'd recommend updating the styles so you can remove the inner span element.
I use a custom link component that does a few things (not shown); one is smooth scroll to hash routes if the browser supports smooth scrolling (not Safari).
import NextLink, { LinkProps } from "next/link";
import { HTMLProps, MouseEvent, FC } from "react";
export const Link: FC<LinkProps & HTMLProps<HTMLAnchorElement>> = ({ as, children, href, replace, scroll, shallow, passHref, ...rest}) => {
const onClick = (event: MouseEvent<HTMLAnchorElement>) => {
if (href.startsWith("#")) {
event.preventDefault();
const destination = document.getElementById(href.substring(1));
if (destination) destination.scrollIntoView({ behavior: "smooth" });
}
};
return (
<NextLink as={as} href={href} passHref={passHref} replace={replace} scroll={scroll} shallow={shallow}>
<a href={href} {...rest} onClick={onClick}>
{children}
</a>
</NextLink>
);
};
I removed new lines to condense the code block
If you went with the above approach, don't include the anchor tag since it's automatically included.
import { Link } from "./custom/path/link"
<Link href="#enews">Get started</Link>
Two points here:
As per the nextjs, passHref has to be used if a custom element is used as a child of Link tag instead of an anchor tag.
As per the same docs value of href should be '/#enews' not '#enews'
How do I troubleshoot this problem this deployment issue? I am following this tutorial. My node_modules and .next are ignored and not pushed to github. It works locally but can't seem to deploy. I have supplied both the component code as well as the page it's exported on. Let me know if you can see what I am missing.
https://www.youtube.com/watch?v=V4SVNleMitE
deployment errors
Error occurred prerendering page "/components/BlogPosts". Read more: https://nextjs.org/docs/messages/prerender-error
TypeError: Cannot read property 'fields' of undefined
at BlogPosts (/vercel/path0/.next/server/chunks/130.js:39:12)
at d (/vercel/path0/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:33:498)
at bb (/vercel/path0/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:36:16)
at a.b.render (/vercel/path0/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:42:43)
at a.b.read (/vercel/path0/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:41:83)
at Object.exports.renderToString (/vercel/path0/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:52:138)
at Object.renderPage (/vercel/path0/node_modules/next/dist/server/render.js:673:46)
at Object.defaultGetInitialProps (/vercel/path0/node_modules/next/dist/server/render.js:315:51)
at Function.getInitialProps (/vercel/path0/.next/server/pages/_document.js:645:16)
at Object.loadGetInitialProps (/vercel/path0/node_modules/next/dist/shared/lib/utils.js:69:29)
component blog posts
export default function BlogPosts({post }) {
const {title, information,slug , thumbnail} = post.fields
return (
<div>
<div className='container w-50 h-25 mt-4'>
<Image
className='nav'
src={'https:' + thumbnail.fields.file.url}
width={thumbnail.fields.file.details.image.width}
height={thumbnail.fields.file.details.image.height}
/>
</div>
<div>
<div>
<h4 className=''>{title}</h4>
<Link href={'/contentslug/' + slug}>
<a className='btn btn-primary text-white'>Read more</a>
</Link>
</div>
</div>
</div>
)
}
Pages/Posts
import {createClient} from 'contentful'
import BlogPosts from './components/BlogPosts'
import Nav from './components/Nav'
import Logo from './components/Logo'
export async function getStaticProps() {
const client = createClient({
space: process.env.NEXT_PUBLIC_CONTENTFUL_ID,
accessToken: process.env.NEXT_PUBLIC_CONTENTFUL_TOKEN,
})
const res = await client.getEntries({content_type: 'posts'})
return {
props: {
posts: res.items ,
revalidate: 1
}
}
}
export default function Home({posts}) {
console.log(posts);
return (
<div>
<Logo/>
<Nav/>
<div className="container text-center display-5">
{posts.map(post => (
<BlogPosts key={post.sys.id} post={post}/>
))}
</div>
</div>
)
}
You have fields of undefined. this might be caused because of some strange deploying behavior if you are 100% sure your code works.
How to fix (probably):
Build your project locally. if it works, follow the next step
Comment your code in BlogPosts, inside the exported component. The code must work, so your exported component will be empty but working.
Push this code to Vercel.
Uncommit your code. (done at point 2)
Push again.
P.S. this behavior with API is sometimes caused because of API middleware you reworked.
Problem
I'm doing some development using Next.js and ZKSwap API, but I can't figure out how to use the ABI of the deployed smart contract.
Specifically, I want to call this DepositETH.
https://en.wiki.zks.org/interact-with-zkswap/make-transaction#deposit-eth
And it seems that I need to configure this ABI to call it, but I don't know how to configure it.
https://en.wiki.zks.org/interact-with-zkswap/make-transaction#abis
What I Did
I implemented it as follows, but it didn't work.
import { Wallet, Contract, utils } from 'ethers'
import Web3 from 'web3'
import zkswapABI from '../src/zkswap.ABI.json'
const Web3EthAbi = require('web3-eth-abi');
export default function zkswap() {
//try2
let ABI = zkswapABI
const wallet = new Wallet('0x1c1a49fea9a4ede1dc8e582639f498d41fa3c4a9e2ab2b9d740a4a3ec14e1cbf')
const contract = new Contract('0x8ECa806Aecc86CE90Da803b080Ca4E3A9b8097ad', ABI, wallet)
async function depositETH(amount) {
const tx = await contract.depositETH(wallet.address, {
value: utils.parse(amount)
})
return tx
}
depositETH('0.5').then(console.log)
return (
<div>
<section className="h-screen w-4/5 max-w-5xl mx-auto flex items-center justify-center flex-col">
<h1 className="mb-4 text-green-500 text-3xl">sample</h1>
<p className="mb-2 text-center"> ZKSwap </p>
<button className="btn-blue" onClick={depositETH}> Deposit ETH</button>
</section>
</div>
)
}
Error
In fact, when I tried to 'yarn dev', I got an error like this
TypeError: ethers__WEBPACK_IMPORTED_MODULE_1__.utils.parse is not a function