load splash screen before nextjs - reactjs

I have a NextJS website and I want to add a Splash Screen for before website is loaded
but because the Splash Screen is also in the NextJS code, it will loading when nextjs rendered on the server and the JS downloaded and executed on the client. in fact, it's useless because it will execute after the page is ready!
how can I do the Splash Screen before react completely loaded and executed ?
I also use nginx for proxy_pass

use this code
useEffect(() => {
const handleStart = () => { setPageLoading(true); };
const handleComplete = () => {
setPageLoading(false);
};
router.events.on('routeChangeStart', handleStart);
router.events.on('routeChangeComplete', handleComplete);
router.events.on('routeChangeError', handleComplete);
}, [router]);
and use pageLoding for show splash

For loading screen:
import React from 'react'
import useSWR from 'swr'
const fetcher = (url) => fetch(url).then((res) => res.json());
// your main function
export default function Profile() {
//for relative and absolute paths
const { data, error } = useSWR('/api/user', fetcher)
if (error) return <div>failed to load</div>
//for the loading you can create your custom component and insert instead of div, like this you keep same styling
if (!data) return <div>loading...</div>
if (data) return <div>hello {data.name}!</div>
}
Don't use useEffect hook, use this lib, better code and functionnality.

You have multiple possibility
You can start your Next Application on a page that contain a simple shimmer(splash screen), then replace the URL by url that contain SSR, and finally remove loading page for indexing with robot.txt. You can read more about this tips there.
You can insert inside on ... tag a CSS to show a loader(your splash screen). Then when the SSR function will be in loading the loader will be hide but when the browser download index.html(first file loaded, that contain style tag) the loader will be show before the browser download another assets(images, js, etc) and load it. You can read more about this tips there
The first tips will show loader fast than the second tip but require more steep(create another page, replace url, remove loader page for indexing)

You can do it by using DOMContentLoaded event, here an example:
In your _app.tsx and outside your function:
if (typeof window !== "undefined") {
document.addEventListener("DOMContentLoaded", () => {
// your code here ..
}
}

Related

NextJs script component should hide on a specific page

In my React/NextJS app I added a new component to show a FreshDesk widget.
This component should only show on some specific pages after a login but when I logout from the app the widget is still visible until I refresh the page
The component
import Script from 'next/script';
const FreshDesk = () => {
const { freshDesk } = useConfig();
return (
<>
{console.log(freshDesk)}
<Script
src={`https://widget.freshworks.com/widgets/${freshDesk}.js`}
strategy="lazyOnload"
/>
<Script id="my-script" strategy="afterInteractive">
{` window.fwSettings={
'widget_id':${freshDesk},
};
!function(){if("function"!=typeof window.FreshworksWidget){var n=function(){n.q.push(arguments)};n.q=[],window.FreshworksWidget=n}}()
`}
</Script>
</>
);
};
export default FreshDesk;
It is just called <FreshDesk /> when it needs it.
The login page doesn't have the widget call but soon as I log out the widget is still there until I refresh and don't know what to do about it.
It looks like you can use FreshworksWidget("destroy") to destroy the widget.
source
I would propose you add the following useEffect (disclaimer: I don't know the library so this might not work perfectly)
useEffect(()=>{
// create the widget if the script is loaded already
if(window.FreshworksWidget){
window.FreshworksWidget("boot");
}
// when unmounting the component, destroy the FreshworksWidget
return ()=>{
if(window.FreshworksWidget){
window.FreshworksWidget("destroy");
}
}
}, []);
Decided to answer my own question by showing the solution I found working for me.
What I did was to add in the login component this code
useEffect(() => {
if (document.querySelector('#launcher-frame')) {
document.querySelector('#launcher-frame').style.display = 'none';
}
}
and in the component, I was using the widget
useEffect(() => {
if (document.querySelector('#launcher-frame')) {
document.querySelector('#launcher-frame').style.display = 'block';
}
}, []);
In this way, I just hide it from my login page but showing everywhere else

Website renders like desktop on mobile, only when first loaded or is refreshed

I have created a website that uses media queries and is responsive when tested from the Dev tools in browser. However it reverts back to its desktop-like state on reloading. If i click on a link that redirects me to another page, it is displays the second page perfectly as expected. Same for when i go "back". The homepage is now magically responsive.
[View the issue : ]https://reach-tech-interns-page1.vercel.app/
Upon opening on mobile, this link doesn't seem responsive. But click on testimonials and go back, and the homepage is now responsive. If I reload, the mobile site breaks again.
I used Next.js and Chakra UI.
[Github Code:] https://github.com/inferno080/Reach-Tech-Interns-Page
The issue was with Chakra UI's useMediaQuery() hook. Writing a custom hook solved this issue
const useMediaQuery = (query) => {
const [matches, setMatches] = useState(false);
useEffect(() => {
const media = window.matchMedia(query);
if (media.matches !== matches) {
setMatches(media.matches);
}
const listener = () => setMatches(media.matches);
window.addEventListener("resize", listener);
return () => window.removeEventListener("resize", listener);
}, [matches, query]);
return matches;
}
export default useMediaQuery;

How to check the status code of URL in iFrame in React?

I am using iframe in react component.I want to check if the url has responded 200 and loaded completely and want to handle error and loading scenarios. I tried to access the iframe id but it's throwing corss origin frame error. Please suggest
If you want add a loading before iframe loaded completely you can handle it by checking when docuemnt of iframe loaded document.getElementById('myframe').contentWindow.document
you can create a function in your react component and check iframe like this:
const [ loading, setLoading ] = useState(true);
const checkIframe = () => {
const iframeDocument = document.getElementById('myframe').contentWindow.document;
if(iframeDocument){
setLoading(false);
} else{
setTimeout(() => {
checkIframe();
}, 1000);
}
}

White page after fresh build using React Route-based code splitting

The app is using react and React Route-based code splitting: https://reactjs.org/docs/code-splitting.html#route-based-code-splitting
The app is working fine. A user is on the homepage.
Then I do a change in the code and build the app again.
User is clicking on a link, and he is landing on a white page.
Of course, the bundle has changed, and loading the new page (thanks to React.lazy) will drop an error.
Uncaught SyntaxError: Unexpected token <
How can I prevent that and show for example: "Site has been updated, please reload" instead of a white page?
This is built off Alan's comment, which doesn't quite solve the problem of the original question. I faced a similar issue where a build done on a server changed all the file names of the bundles I was loading using React.lazy() and a user who didn't refresh their page would be looking for bundles that no longer exists, resulting in the error he describes.
Again, this is mostly based off Alan's code but solves the problem nicely...
export default function lazyReloadOnFail(fn) {
return new Promise(resolve => {
fn()
.then(resolve)
.catch(() => {
window.location.reload();
});
});
}
const Report = React.lazy(() => lazyReloadOnFail(() => import('./views/Reports/Report')));
Solution is:
Did you know that the import(...) function that we use on lazy is just a function that returns a Promise? Which basically means that you can chain it just like any other Promise.
function retry(fn, retriesLeft = 5, interval = 1000) {
return new Promise((resolve, reject) => {
fn()
.then(resolve)
.catch((error) => {
setTimeout(() => {
if (retriesLeft === 1) {
// reject('maximum retries exceeded');
reject(error);
return;
}
// Passing on "reject" is the important part
retry(fn, retriesLeft - 1, interval).then(resolve, reject);
}, interval);
});
});
}
Now we just need to apply it to our lazy import.
// Code split without retry login
const ProductList = lazy(() => import("./path/to/productlist"));
// Code split with retry login
const ProductList = lazy(() => retry(() => import("./path/to/productlist")));
If the browser fails to download the module, it'll try again 5 times with a 1 second delay between each attempt. If even after 5 tries it import it, then an error is thrown.
Thanks to Guilherme Oenning from: https://dev.to/goenning/how-to-retry-when-react-lazy-fails-mb5

Nextjs check if initial render was done on server side

I have an image lazy load component that just renders the image src when on the server, and renders a loader when on client pending when the actual image is lazyloaded.
The problem.
After the initial render and client side takes over, the image src mismatch. This is because the server set the actual src, but the client is setting the loader (placeholder).
Question.
Is there a way to detect that this initial render was server rendered? just before the client renders/mounts
You can find out if it is currently executed on the server by checking for req attribute inside getInitialProps
Example page code
function Page({ isServer }) {
return <div>Is this page on the server? - {isServer ? 'YES' : 'NO'}</div>;
}
Page.getInitialProps = async ({ req }) => {
return { isServer: !!req };
};
export default Page;
Some info on official repo about isServercheck
You can check that typeof Window === 'undefined'
The fix is to use useEffect as described in the Next.js docs at https://nextjs.org/docs/messages/react-hydration-error
do this:
import { useState, useEffect } from 'react'
function AnyComponent() {
const [isSSR, setIsSsr] = useState(true)
console.log(`isSSR: `, isSSR);
useEffect(() => setIsSsr(false))
return (
<span>Is SSR? {isSSR ? 'Yes!' : 'No!'}</span>
)
}
Obviously, this trivial example will update so quickly that you would only ever see "Is SSR? No!" but the first render will be yes. Check the console.
Why? useEffect is only executed in the browser.

Resources