How can I display a React web page with Three JS - javascript

To clarify I am using React Three Fibre/drei, I have a scene and want to display some text as the landing page. I have a component Home that is meant to be the html webpage, but it is not working as expected:
import Home from './pages/Home.jsx'
function App() {
const CanvasContainer = styled(Box) ( () => ({
width: '100%',
height: '100%',
}))
return (
<CanvasContainer>
<Home></Home>
<Canvas dpr={window.devicePixelRatio}>
<gridHelper args={[200,50]}/>
<axesHelper args={[5]}/>
<Suspense fallback={null}>
<OrbitControls
target={[-1,0,1]}
enableZoom={true}
enablePan={true}
enableRotate={true}
zoomSpeed={0.6}
panSpeed={0.5}
rotateSpeed={0.4}
/>
<Earth/>
<MoonAxis/>
</Suspense>
</Canvas>
</CanvasContainer>
)
}
export default App
Depending on if I import Home with curly braces or not I get an error Uncaught SyntaxError: The requested module ____ does not provide an export named 'default'.
This is what Home looks like:
import React from 'react'
const Home = () => {
return (
<div>Home</div>
)
}
export default Home

Related

Loading page on nextjs 13

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.

react/no-multi-comp is showing up as warnings

I am using hook router 1.2.5 and I have a very simple home page as below:
import { useRoutes } from "hookrouter";
import React from "react";
import Nav from "./pages/Nav";
import AboutPage from "./pages/About";
const HomePage = () => {
const routeResult = useRoutes({
"/about": () => <AboutPage />
});
return (
<div fluid>
<div xs={3} md={1} lg={1} className="nav-container">
<Nav />
</div>
<div xs={9} md={11} lg={11}>
{routeResult || <AboutPage />}
</div>
</div>
);
};
export default HomePage;
But when I run lint, I see below warnings show up.
8:10 warning Component definition is missing display name react/display-name
8:10 warning Declare only one React component per file react/no-multi-comp
I know I can disable these eslint warnings. But I would like to know how to fix them. For example, I don't have another component in my file. So why would it show react/no-multi-comp warning, or did I miss something? Any helps are appreciated.
UPDATE
I was able to fix react/display-name by replacing the arrow function as below:
const routeResult = useRoutes({
"/about"() {
return <AboutPage />;
}
});

How to use vanta with nextjs?

I am trying to use vanta with next.js, following this guide. It works completely fine with the Net Effect, however, when I try to use the Globe Effect, I get
[VANTA] Init error TypeError: r.Geometry is not a constructor
at h.onInit (vanta.globe.min.js:1)
at h.init (vanta.globe.min.js:1)
at new r.VantaBase (vanta.globe.min.js:1)
at new h (vanta.globe.min.js:1)
at r.<computed> (vanta.globe.min.js:1)
I have isolated Vanta into an Background Component
//Background.js
import { useState, useRef, useEffect } from "react";
import NET from "vanta/dist/vanta.globe.min"
import * as THREE from "three";
export default function Background({ width, height, children }) {
const [vantaEffect, setVantaEffect] = useState(0);
const vantaRef = useRef(null);
useEffect(() => {
if (!vantaEffect) {
setVantaEffect(
NET({
THREE,
el: vantaRef.current,
})
);
}
return () => {
if (vantaEffect) vantaEffect.destroy();
};
}, [vantaEffect]);
return (
<div ref={vantaRef}>{children}</div>
)
}
And added the THREE script into my _app.js
import '../styles/globals.css'
import Head from "next/head";
import Navbar from "../components/Navbar";
import { useEffect } from "react";
export default function App({ Component, pageProps }) {
useEffect(() => {
const threeScript = document.createElement("script");
threeScript.setAttribute("id", "threeScript");
threeScript.setAttribute(
"src",
"https://cdnjs.cloudflare.com/ajax/libs/three.js/r121/three.min.js"
);
document.getElementsByTagName("head")[0].appendChild(threeScript);
return () => {
if (threeScript) {
threeScript.remove();
}
};
}, []);
return (
<>
<Head>
<title>BrainStorm Tutoring</title>
</Head>
<Navbar />
<Component {...pageProps} />
</>
)
}
and used it like so
//index
import Background from "../components/Background";
export default function Home() {
return (
<Background height="400" width="400">
<h1 className="text-white text-8xl text-left p-36">Fish Bowl</h1>
</Background >
)
}
Is it something wrong with THREE, or is it that next.js can't support vanta?
I have that issue with Halo, so i think the THREE object was not available or was not defined in the HALO.js file.
So i go to the official github repo of Vanta and take the source of Halo and Net (the tutorial effect) file, and i found constructor was missing in the Halo file. So i take the one of Net and put in the Halo file.
constructor(userOptions) {
THREE = userOptions.THREE || THREE;
super(userOptions);
}
Then i import my custom Halo file for the effect and it works.
I was playing around with this and found that, if I keep the Three.js version to 122. I don't get the error. Apparently any version after that has a breaking change.

React Props not passing down to children components?

I am trying to learn React so please bear with me!
I am following a tutorial to help me understand react and how you can pass down components.
I am trying to pass props down 2 levels, but when I render the code on the third element, nothing appears on the page. Using React Dev tools on chrome, it seems that the props are loading on the Tweets.js component rather than the Tweet.js component.
Can anybody tell me whats wrong? The order is App.js > Tweets.js > Tweet.js
For ref, I am following the following tutorial, it is around the 15 min mark.
React State and Props | Learn React For Beginners Part 4
App.js
import './App.css';
import Tweets from './components/Tweets';
import React from 'react';
function App() {
const name=["Name1", "Name2", "Name3"];
const age=["21", "22", "24"]; /* Data is created here */
return (
<div className="App">
<Tweets me={name} age={age} />{/*Data is added to component*/ }
</div>
);
}
export default App;
Tweets.js
import Tweet from './Tweet';
const Tweets = (props) => (
<section>
<Tweet />
</section>
);
export default Tweets;
Tweet.js
const Tweet = (props) => (
<div>
<h1>{props.me}</h1>
<h1>{props.age}</h1>
</div>
);
export default Tweet;
You would need to transfer props through your Tweets component:
const Tweets = (props) => (
<section>
<Tweet {...props} />
</section>
);

Using APIs in a React Template

I am learning the ropes of React and JavaScript. I started by grabbing a free template I found from GitHub. After creating a few other pages, I connected the app to a Django back end and created a model with two entries.
The objective is to be able to display the information from the model like title, objective, etc. I'm also new to using APIs to get this information, so I've been looking through various places online, but I just can't figure out how to fit in the code examples online with the code I have from the template from GitHub.
One of the places I've looked: https://reactjs.org/docs/faq-ajax.html
Below is Hero.js. This is routed to the home page and it's just what the template provider named it. The code example provided above and in many other places I've looked puts all their code in App.js. I know they're just doing that for demonstration purposes, but I'm not sure how to fit it into the template code.
import React, { useState } from 'react';
import classNames from 'classnames';
import { SectionProps } from '../../utils/SectionProps';
import ButtonGroup from '../elements/ButtonGroup';
import Button from '../elements/Button';
import Image from '../elements/Image';
import { Link } from 'react-router-dom';
const propTypes = {
...SectionProps.types
}
const defaultProps = {
...SectionProps.defaults
}
const Hero = ({
className,
topOuterDivider,
bottomOuterDivider,
topDivider,
bottomDivider,
hasBgColor,
invertColor,
...props
}) => {
const outerClasses = classNames(
'hero section center-content',
topOuterDivider && 'has-top-divider',
bottomOuterDivider && 'has-bottom-divider',
hasBgColor && 'has-bg-color',
invertColor && 'invert-color',
className
);
const innerClasses = classNames(
'hero-inner section-inner',
topDivider && 'has-top-divider',
bottomDivider && 'has-bottom-divider'
);
return (
<section
{...props}
className={outerClasses}
>
<div className="container-sm">
<div className={innerClasses}>
<div className="hero-content">
<h1 className="mt-0 mb-16 reveal-from-bottom" data-reveal-delay="200">
BlueBird <span className="text-color-primary">Teaching</span>
</h1>
<div className="container-xs">
<p className="m-0 mb-32 reveal-from-bottom" data-reveal-delay="400">
An open source approach to education.
</p>
<div className="reveal-from-bottom" data-reveal-delay="600">
<ButtonGroup>
<Button tag="a" color="primary" wideMobile>
<Link to="/About">How This Works</Link>
</Button>
<Button tag="a" color="dark" wideMobile>
<Link to="/Test">Other Open Source Resources</Link>
</Button>
</ButtonGroup>
</div>
</div>
</div>
<div className="hero-figure reveal-from-bottom illustration-element-01" data-reveal-value="20px" data-reveal-delay="800">
<h2>Current Focus:</h2>
<h3 style={{ color: '#5b92e5' }}>(title)</h3>
<p style={{ textAlign: 'left', color: 'white' }}><strong>Objective: </strong>(Objective goes here)</p>
<p style={{ textAlign: 'left', color: 'white' }}>(Description goes here)</p>
<p style={{ textAlign: 'left', color: 'white', fontSize: 15 }}>The expected completion date of this focus is: (expected_completion_date)</p>
<h3>Preview</h3>
<Image style={{ padding: '30px' }}
src={require('./../../assets/images/Screenshot from 2020-08-03 07-52-33.png')}
alt="Hero"
width={896}
height={504} />
<Image
src={require('./../../assets/images/Screenshot from 2020-08-03 07-53-08.png')}
alt="Hero"
width={896}
height={504} />
</div>
</div>
</div>
</section>
);
}
Hero.propTypes = propTypes;
Hero.defaultProps = defaultProps;
export default Hero;
If needed, below is App.js.
import React, { useRef, useEffect } from 'react';
import { useLocation, Switch } from 'react-router-dom';
import AppRoute from './utils/AppRoute';
import ScrollReveal from './utils/ScrollReveal';
import ReactGA from 'react-ga';
// Layouts
import LayoutDefault from './layouts/LayoutDefault';
// Views
import Home from './views/Home';
import Test from './views/test';
import About from './views/About';
import Contact from './views/Contact';
// Initialize Google Analytics
ReactGA.initialize(process.env.REACT_APP_GA_CODE);
const trackPage = page => {
ReactGA.set({ page });
ReactGA.pageview(page);
};
const App = () => {
const childRef = useRef();
let location = useLocation();
useEffect(() => {
const page = location.pathname;
document.body.classList.add('is-loaded')
childRef.current.init();
trackPage(page);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [location]);
return (
<ScrollReveal
ref={childRef}
children={() => (
<Switch>
<AppRoute exact path="/" component={Home} layout={LayoutDefault} />
<AppRoute exact path="/test" component={Test} layout={LayoutDefault} />
<AppRoute exact path="/about" component={About} layout={LayoutDefault} />
<AppRoute exact path="/contact" component={Contact} layout={LayoutDefault} />
</Switch>
)} />
);
}
export default App;
Thanks for any help and explanations!
So you just want to get your data from API and use it in your application.
Here is an little example for you with comments
import React, { useState, useEffect } from "react";
export default function Example() {
// Define our datas variable in state as an empty Array
const [datas, setDatas] = useState([]);
// useEffect will called after component will be rendered
useEffect(() => {
// Fetch our data from our API
fetch("https://jsonplaceholder.typicode.com/todos/")
// Resolve the responsove data
.then((response) => response.json())
.then((json) => {
// Show data in console
console.log(json)
// Set our API data to our datas array
setDatas([...json]);
});
}, []);
return (
<div>
<ul>
{/*
map is a build-in javascript function too loop through objects like foreach
So we just loop our array and render in our application
*/}
{datas.map((data, i) => (
<li key={i}> {data.title} </li>
))}
</ul>
</div>
);
}
I use javascript Fetch API function to get data from API but if you want, you can use something like Axios too.
If we want to use axios we just need to change useEffect like this for example;
First we need to install axios
npm install axios
Then, import or require axios
import axios from "axios";
// or
const axios = require('axios');
After these steps, just change useEffect function like this;
axios.get("https://jsonplaceholder.typicode.com/todos/")
.then(function (response) {
// handle success and show data in console
console.log(response.data);
// Set our API data to our datas array
setDatas([...response.data]);
})
.catch(function (error) {
// handle error
console.log(error);
})
.then(function () {
// always executed
});
Javascript MAP: Array.prototype.map() - Mozilla Developers
Fetch API: Fetch API - Mozilla Developers
Axios: Axios Github Page
Axios vs Fetch API: Fetch vs. Axios.js for making http requests
Also I would suggest you to build your app from scratch rather than using a template to understand better and remember I just gave you a simple example, if you wanna build something for production you may want to build a different structure for your API requests.
I hope I could help, have a great day :)

Categories

Resources