0

I am trying to achieve page loading (actually fake page loading) with established time out up to 1500s (my control). using reach/router library, just like Jack's website example here https://jacekjeznach.com (click on every page to see the loading).

I've pretty much succeed page loading, But not quite. The page load only happen when I refresh the page. Just because step only work refresh or actaul page-to-page not SPA routes. The objective is to have "fake page load" when switching routes or other word fetching components from nav links, So here's what I have so far...


import React, { useEffect, useState, lazy, Suspense } from "react";
import ReactDOM from "react-dom";
import { Link, Router } from "@reach/router";
import styled from "styled-components";

import "./styles.css";

function App() {
  const [pageRender, setPageRender] = useState(true);

  useEffect(() => {
    const loadingTime = setTimeout(() => setPageRender(false), 1500);
    return () => clearTimeout(loadingTime);
  }, []);
  return <div>{pageRender ? <Loader /> : <Route />}</div>;
}

//-----------Router (Reach Router)---------------------------
function Route({ children }) {
  return (
    <div>
      <SetNav>
        <Link to="/">Home</Link>
        <Link to="/About">About</Link>
        <Link to="/Contact">Contact</Link>
      </SetNav>
      <Router>
        <Home path="/" />
        <About path="/About" />
        <Contact path="/Contact" />
      </Router>
    </div>
  );
}

const SetNav = styled.nav`
  display: flex;
  align-items: center;
  background-color: #ddd;
  height: 50px;
  a {
    padding: 0 10px;
  }
`;

// -------- Home (Components)----------------------

function Home() {
  return (
    <div>
      <h1>Home Page</h1>
    </div>
  );
}

// -------- About (Components)----------------------
function About() {
  return (
    <div>
      <h1>About Page</h1>
    </div>
  );
}

// -------- Contact (Components)----------------------
function Contact() {
  return (
    <div>
      <h1>Contact Page</h1>
    </div>
  );
}

//--------- Loader (Text/Spinner/Processbar)--------------
function Loader() {
  return <div>Loading...</div>;
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);


I had feeling, those syntax useEffect(setTimeout(()=> (...), 1500) or useEffect(setInterval(()=> (...), 1500) could work for routes but I am unable to come better solution.

I've also tried Suspense/Lazy and yes it worked work too, but Unfortunately, I have no control with loading time (delay time).

import React, { Suspense } from "react";
import ReactDOM from "react-dom";
import { Link, Router } from "@reach/router";
import styled from "styled-components";

const Home = React.lazy(import('./compments/Home'))
const About = React.lazy(import('./compments/About'))
const Contact = React.lazy(import('./compments/Contact'))

<div>
   <Suspense fallback={<Loader/>}/>
      <nav>
        <Link to="/">Home</Link>
        <Link to="/About">About</Link>
        <Link to="/Contact">Contact</Link>
      </nav>
      <Router>
        <Home path="/" />
        <About path="/About" />
        <Contact path="/Contact" />
      </Router>
    </div>
    <Suspense />

I have thought about using setTimeout for Suspense but couldn't come in mind how to set this up.

I am running out of ideas, And ideas or suggestion? Your help is appreciated, thanks in advance.

sirrus
  • 341
  • 1
  • 7
  • 16
  • Are you using redux or anything else to control the global state? – joseluismurillorios Sep 02 '19 at 00:09
  • I haven't tried yet, but i found this post, https://github.com/ReactTraining/react-router/issues/2365. Seems that you can try use `onEnter` so that you can put your time delay there before switching. – windmaomao Sep 02 '19 at 02:47
  • @joseluismurillorios -- I am not using Redux. Redux is something I want to avoid for few number of components without fetching data. – sirrus Sep 02 '19 at 15:35
  • @windmaomao - I've looked into that, Its for react-router. I am using ***reach***-router. Howeever, I was notified Ryan Florence may be working on that too for reach-router. – sirrus Sep 02 '19 at 15:40

1 Answers1

2

You could write a wrapper component and then wrap all of your pages with it.. It is quick and dirty, but it works..

Live demo can be found here

Loader Wrapper Component:

export default function Loader({children}) {
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    setTimeout(() => {
      setLoading(false);
    }, 3000)
  }, []);

  return(
    <div>
    {loading
      ? <CircularProgress />
      : children}
    </div>
  );
}

Loader Wrapper in use:

export default function Crayons(props) {
  return (
    <Loader>
        <div>
          <h1>Crayons Page</h1>
          {props.match.params.id
            ? <p>Crayon ID: {props.match.params.id}</p>
            : ""}
        </div>
    </Loader>
  );
}
Matt Oestreich
  • 8,219
  • 3
  • 16
  • 41
  • 1
    Oh Brilliant!! wrapping around `{children}` why didn't I think! This solved my problem, fast. Thank you for helping! – sirrus Sep 02 '19 at 15:42