I am a novice coder trying to work through a Typescript/NextJS project that uses Auth0. It is currently set up to take users to a page (code below) that just has a login button that takes you to the Auth0 page.
This is an unnecessary step. How can I edit this to directly take the user to the Auth0 auth page upon navigating to the URL?
import "../styles/stripe.css";
import "../styles/globals.css";
import "../styles/App.css";
import "../styles/index.css";
import "../styles/progress.css";
import { FC, StrictMode } from "react";
import { getCLS, getFCP, getFID, getLCP, getTTFB } from "web-vitals";
import { useUser, UserProvider } from "#auth0/nextjs-auth0";
import type { AppProps } from "next/app";
import { ToastContainer } from "react-toastify";
import { useRouter } from "next/router";
import Head from "next/head";
import Header from "../views/Header";
const SignInRequired: FC = ({ children }) => {
const { user, error, isLoading } = useUser();
const router = useRouter();
if (isLoading) return <div />;
if (error) return <div>{error.message}</div>;
if (!user) {
return (
<>
<div className="container flex-col flex-center">
<h1>AppCo</h1>
<h2>Please sign in.</h2>
<button
className="card-test"
onClick={() => router.push("/api/auth/login")}
>Login</button>
<p>Questions?</p>
<p>hi#appco.com</p>
</div>
</>
);
}
return (
<>
{children}
</>
);
};
export default function App({ Component, pageProps }: AppProps) {
return (
<StrictMode>
<UserProvider>
{/* Default SEO. */}
<Head>
<title>AppCo</title>
<meta name="description" content="AppCo" />
<link rel="icon" href="/favicon.ico" />
</Head>
<div className="w-full">
{/* Max layout width. */}
<Header />
<SignInRequired>
<main className="w-full py-8">
<Component {...pageProps} />
</main>
<ToastContainer
autoClose={2000}
/>
</SignInRequired>
</div>
</UserProvider>
</StrictMode>
);
}
/**
* Use Web Vitals.
*
* #see https://nextjs.org/docs/advanced-features/measuring-performance
*/
export const reportWebVitals = (onPerfEntry) => {
if (onPerfEntry && onPerfEntry instanceof Function) {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
}
};
Currently the code is saying "if not a user, return the sign in button".
Instead of returning that sign in button, you can redirect using Router assuming this is your next.js file.
You'll need to also import router:
import Router from 'next/router'
// or add push to your current line
import { useRouter, push } from "next/router";
if (!user) {
Router.push('/new-route')
}
I'm afraid I'm not a next.js expert but hope this gets the job done for you! Good luck!
Related
I am attempting to create a ProtectedRoutes component, however, I seem to have created an infinite loop somewhere that I can't seem to figure out. I'm a beginner.
It should check if there is a cookie stored, and if so, go to the component. If not, it should navigate back to the main page.
ProtectedRoutes.js
import React, { Component, useState } from "react";
import { Route, Navigate } from "react-router-dom";
import Cookies from "universal-cookie";
const cookies = new Cookies();
export default function ProtectedRoutes({component: Component, ...rest}) {
const [auth, setAuth] = useState(false);
//get cookie from browser if logged in
const token = cookies.get("TOKEN");
if (token) {
setAuth(true);
};
return auth ? <Component /> : <Navigate to="/" />
}
App.js
import { Container, Col, Row } from "react-bootstrap";
import "./App.css";
import Register from "./Register";
import Login from "./Login";
import { Routes, Route } from "react-router-dom";
import Account from "./Account";
import FreeComponent from "./FreeComponent";
import AuthComponent from "./AuthComponent";
import Private from "./ProtectedRoutes";
import ProtectedRoutes from "./ProtectedRoutes";
function App() {
return (
<Container>
<Row>
<Col className="text-center">
<h1 className="header">React Authentication Tutorial</h1>
<section id="navigation">
Home
Free Component
Auth Component
</section>
</Col>
</Row>
{/* Routes */ }
<Routes>
<Route exact path="/" element={ <Account /> } />
<Route exact path="/free" element={ <FreeComponent /> } />
<Route path="/auth" element={<ProtectedRoutes component={AuthComponent} />} />
</Routes>
</Container>
);
}
export default App;
AuthComponent.js
import React from 'react';
export default function AuthComponent() {
return (
<div>
<h1 className="text-center">Auth Component</h1>
</div>
);
}
Yow problem Is heaw.
export default function ProtectedRoutes({component: Component, ...rest}) {
const [auth, setAuth] = useState(false);
//get cookie from browser if logged in
const token = cookies.get("TOKEN");
if (token) {
setAuth(true);
};
return auth ? <Component /> : <Navigate to="/" />
}
You need yo put setAuth in a useEffect
export default function ProtectedRoutes({component: Component, ...rest}) {
const [auth, setAuth] = useState(false);
React.useEffect(()=>{
const token = cookies.get("TOKEN");
if (token) {
setAuth(true);
}
},[auth]);
return auth ? <Component /> : <Navigate to="/" />
}
In ProtectedRoutes component, you're setting a state (setAuth in this case) directly inside the component, this is what happens when you do that:
React re-renders a component every time a state change is detected thus when you wrote
export default function ProtectedRoutes({component: Component, ...rest}) {
...
if (token) {
setAuth(true);
};
...
}
you're running setAuth(sets a new state true) every time the component renders(re-renders) and in turn, re-rendering the component every time because of the state change which is why have an infinite loop there.
, this works like this:
It runs everytime a dependency changes(passed as an array), and when you pass an empty array it runs just twice - when the component mounts(renders the first time) and when it unmounts.
What you need to do is to pass an empty array as a dependency as below
import { useEffect } from 'react'
export default function ProtectedRoutes({component: Component, ...rest}) {
...
useEffect(() => {
if (token) {
setAuth(true);
};
}, [])
...
}
this setAuth just once when the component mounts
I have to clone a website using ReactJs which only works on desktop. When it is viewed in a mobile view or Tablet...it shows "SITE NOT AVAILABLE ON MOBILE". I want to do that too....but it is not working on my site
import "./App.css";
import Navbar from "./components/Navbar";
import Text from "./components/Text";
import Slider from "./components/Slider";
import Wallet from "./components/Wallet";
import Dropdown from "./components/Dropdown";
import MobileTablet from "./components/MobileTablet";
import { BrowserView, MobileView } from "react-device-detect";
import { BrowserRouter as Router } from "react-router-dom";
function App() {
return (
<>
<BrowserView>
<Router>
<Text />
<div className="box">
<Navbar />
<Dropdown />
<div className="box2">
<Slider />
</div>
</div>
<div className="box3">
<Wallet />
</div>
</Router>
</BrowserView>
<MobileView>
<MobileTablet />
</MobileView>
</>
);
}
export default App;
This is the code for App.js the main part....Can someone help me make my app responsive...since i am very new to this.
If you need any other codes pls let me know
you can use isMobile for conditional rendering
import {isMobile} from 'react-device-detect';
...
if (isMobile) {
return <MobileTablet />
}
``
Look, you can use a State to monitor the viewport of client window, then a useEffect to change it. The property window.innerWidth gives you the width of the client, and then you can specify it to work only under specific conditions:
import { useState, useEffect } from "react";
export default function App() {
const [userIsDesktop, setUserIsDesktop] = useState(true);
useEffect(() => {
window.innerWidth > 1280 ? setUserIsDesktop(true) : setUserIsDesktop(false);
}, [userIsDesktop]);
return (
<div className="App">
{userIsDesktop ? <h1>i'm a desktop</h1> : <h1>i'm a mobile</h1>}
</div>
);
}
As the title says my navbar is not changing the fragments after updating the state. I have no idea how to refresh it and other ideas seems to not work for me. I have tried to change the statements.
All i want to do is, after a user logs in successfully the state changes to true and the navbar updates with the corrent components. Thank you !
Home.js
import React, { useEffect } from 'react'
function Home() {
useEffect(()=>{
if(!localStorage.getItem("loggedIn")){
localStorage.setItem("loggedIn",false);
}
},[]);
return (
<div>
Home
</div>
)
}
export default Home
Login.js
import React from 'react';
import './Login.css';
import Axios from 'axios';
import { useEffect, useState } from "react";
import {useHistory} from 'react-router-dom';
function Login() {
const[username,setUsername] = useState('');
const[password,setPassword] = useState('');
const[errorMessage,setErrorMessage] = useState('');
let history = useHistory();
const login = () =>{
console.log(username);
Axios.post("http://localhost:3001/user/login",{username: username,password: password}).then((response) => {
//console.log(response);
if(response.data.loggedIn){
localStorage.setItem("loggedIn",true);
localStorage.setItem("username",response.data.username);
history.push('/');
}else{
setErrorMessage(response.data.message);
}
});
};
return (
<div className="Login">
<h1>Login to your BugTrack account !</h1>
<div className="LoginForm">
<input type="text" placeholder="USERNAME"
onChange={(event)=>{setUsername(event.target.value)}}/>
<input type="password" placeholder="PASSWORD"
onChange={(event)=>{setPassword(event.target.value)}}/>
<button onClick={login}>Login to you account</button>
<h1 style={{color: "red"}}>{errorMessage}</h1>
</div>
</div>
);
}
export default Login
Navbar.js
import React, { useEffect, useState, Component, Fragment } from 'react';
import './Navbar.css';
function Navbar() {
const [loggedIn, setLoggedIn] = useState(false);
useEffect(()=> {
setLoggedIn(localStorage.getItem("loggedIn"));
},[localStorage.getItem("loggedIn")]);
return (
<div className="Navbar">
Home
{!loggedIn ? (
<Fragment>
Profile
</Fragment>
):(
<Fragment>
Register
Login
</Fragment>
)}
</div>
);
}
export default Navbar;
You want to to use localStorage as a useEffect dependency which isn't supports for React to rerender/update the component. Check this: useEffect do not listen for localStorage - it's like duplicate of your question.
I'm new to React and I'm currently setup my first project using Gatsby. Essentially I'm creating a website that use an API created with Strapi. So far, I would like to load the navbar items using an API call like that: http://localhost:3001/sections, where for sections, I mean the items of the navbar.
For doing so, I have defined an Index page like that:
import React from "react"
import Layout from "../components/layout/layout"
import SEO from "../components/layout/seo"
import BGTState from "../context/bgt/bgtState"
import "../styles/css/begreentannery.css"
const IndexPage = () => {
return (
<BGTState>
<Layout>
<SEO title="Home" />
</Layout>
</BGTState>
)
}
export default IndexPage
the BGTState contains the getSections() method that is used inside Layout:
import React, { useContext, useEffect } from "react"
import PropTypes from "prop-types"
import { injectIntl } from "gatsby-plugin-intl"
import BGTContext from "../../context/bgt/bgtContext"
import { Spinner } from "react-bootstrap"
import Footer from "./footer"
import SearchState from "../../context/search/SearchState"
import Search from "../../components/search"
import NavbarMobile from "../../components/layout/navbarMobile"
import NavbarDesktop from "../../components/layout/navbarDesktop"
const Layout = ({ children, intl }) => {
const bgtContext = useContext(BGTContext)
const { loading, getSections, sections } = bgtContext
useEffect(() => {
getSections()
//eslint-disable-next-line
}, [])
return !loading ? (
<>
<NavbarMobile sections={sections} />
<NavbarDesktop sections={sections} />
<SearchState>
<Search />
<div className="container-fluid">
<div className="main">
{children}
<Footer />
</div>
</div>
</SearchState>
</>
) : (
<div className="container" style={{ height: "100vh" }}>
<div className="row h-100 justify-content-center align-items-center">
<Spinner animation="grow" />
</div>
</div>
)
}
Layout.propTypes = {
children: PropTypes.node.isRequired,
}
export default injectIntl(Layout)
the problem is in the code above, essentially I call useEffect hook which grab the sections from the API. So, until the sections are downloaded, I stop the code like so:
return !loading ? (
this is the getSections() method inside BGTState:
const getSections = async () => {
try {
setLoading()
const res = await axios.get(
`${process.env.API_URL}/sections?_sort=order:ASC`
)
dispatch({
type: GET_SECTIONS,
payload: res.data,
})
} catch (err) {
dispatch({
type: GET_SECTIONS,
payload: err.response.msg,
})
}
}
in the Index page all works fine, but the problem is in the CollectionsPage, infact I have this structure:
import React from "react"
import { injectIntl } from "gatsby-plugin-intl"
import Layout from "../components/layout/layout"
import SEO from "../components/layout/seo"
import BGTState from "../context/bgt/bgtState"
import CollectionState from "../context/collection/collectionState"
import Collection from "../components/collection"
const CollectionsPage = ({ intl }) => {
return (
<BGTState>
<Layout>
<SEO
lang={intl.locale}
title={`${intl.formatMessage({ id: "collections" })}`}
/>
<CollectionState>
<Collection id={1} />
</CollectionState>
</Layout>
</BGTState>
)
}
export default injectIntl(CollectionsPage)
essentially, the component <CollectionState> isn't mounting 'cause in Layout there is the async call on getSections().
So in Collection component, I have:
import React, { useContext, useEffect } from "react"
import CollectionContext from "../context/collection/collectionContext"
import { Link } from "gatsby"
const Collection = ({ id }) => {
const collectionContext = useContext(CollectionContext)
const { loading, collection, getCollection } = collectionContext
useEffect(() => {
getCollection(id)
}, [])
if (loading) return React.Fragment
return (
<div className="container">
<div className="row">
{/*
<img
src={`${process.env.API_URL}${collection.feature_media.url}`}
className="w-100 mt-2 mb-2"
alt={""}
/>*/}
<Link to="#" className="bg-caption bg-no-underline">
fall/winter 20/21
</Link>
</div>
</div>
)
}
export default Collection
which generate that error:
and of course getCollection is not called and will generate other errors in the Collection component
How can I revisit this mechanism? Essentially I have to:
Load all the sections
Load all the components
I want to statically generate my navbar, so that it does not need to fetch from client side.
I am using appollo graphql and my current _app.js looks like this:
import React from 'react';
import Head from 'next/head';
import { ApolloProvider } from '#apollo/react-hooks';
import withData from '../utils/apollo';
import Header from '../components/Header';
import '../assets/css/tailwind.css';
const App = (props) => {
const { Component, pageProps, apollo } = props;
return (
<ApolloProvider client={apollo}>
<Head>
<title>...</title>
<meta name="viewport" content="initial-scale=1.0, width=device-width" />
<meta charset="utf-8"></meta>
</Head>
<Header />
<Component {...pageProps} />
</ApolloProvider>
);
};
export default withData(App);
And my Header component looks like this
import React, { useEffect, useState } from 'react';
import Link from 'next/link';
import Query from '../components/query';
import CATEGORIES_QUERY from '../apollo/queries/category/categories';
const Header = () => {
const [isExpanded, setIsExpanded] = useState(false);
const expandedClasses = isExpanded ? 'flex ' : 'hidden ';
return (
<Query query={CATEGORIES_QUERY} id={null}>
{({ data: { categories } }) => {
return (
<React.Fragment>
<nav
className={`${expandedClasses}`}
>
{categories.map((category, i) => {
return (
<Link
href="/category/[cid]"
as={`/category/${category.id}`}
passHref
key={`nav-link-${i}`}
>
<a className="text-gray-800">
{category.name}
</a>
</Link>
);
})}
</nav>
<button
className="flex"
onClick={() => {
setIsExpanded(!isExpanded);
}}
>
<span className="mb-1 bg-orange-500"></span>
<span className="mb-1 bg-orange-500"></span>
<span className="mb-1 bg-orange-500"></span>
</button>
</React.Fragment>
);
}}
</Query>
);
};
export default Header;
Next.js only allows getStaticProps on page components, I am trying to get a similar functionality on my Header Component.
I tried adding getStaticProps on header component and also on _app.js that did not work.
How can I achieve this?
This was posted recently. Also no need to ever import React itself when using next.
https://github.com/vercel/next.js/discussions/10949![enter image description here](https://i.stack.imgur.com/6hfVo.jpg)