Loading a gif then transition to the web page on reactjs - javascript

I have a react js application when loading a page there is a gif loading at the beginning. I want a way so that the whole website is fully loaded and then the gif will stop and a transition will be made to show a ready website, this transition can be fade or growing circle, currently the gif is hardcoded with a timeout is there a way to do this ?
currently this is the code responsible for loading the gif :
The loader.js file :
import loder from "../assets/gifs/loading.gif"
const Loader = () => {
return (
<div
style={{
background: "#F7D036",
height:'100%',
width:"100%"
}}
>
<br/><br/><br/><br/><br/><br/><br/><br/><br/>
<center>
<img src={loder} height="200" alt=""/></center>
</div>
)
}
The app.js file :
useEffect(() => {
getAllCategories();
setTimeout(() => setLoading(false), 2000);
}, [getAllCategories]);
return (
<Router>
{loading == true ? (
<Loader />
) : (
some code )

we can use the approach of window.onload() event listener, in your case the execution would be like, And also you need to use states to manage them effectively
window.onload = (e) => {
// your state changes here
setLoading(false);
}
The window.onload listener will wait for the entire page to load, and you have to initiate the loader first, and then toggle this function using the useEffect like
useEffect(()=>{
//
setLoading(true);
// wrap the window.onload event inside a function and call it here
windowLoadFunction();
}, [])
Hello max, as per the comment,
so what we can do is that have your loader initiated like you have to set the state of loader as true by default, so initially your page will start loading,
So you can use the useState property to set it to true by deault, and add a css class to the loader and also add an id so we can fetch it with document.getElementById(), and so as stated in the answer, when we toggle the loader state to false, we can change the class of the loader by accessing it like document.getElementById("loader").className = "your animated css fade out class", and that's it, so, if you want your loader to fade away first then call the class change method first and then you can call the setLoader class to false,
const [loading, setLoader] = useState(true);
useEffect(()=>{
window.onload = ()=>{
// changing class of the gif to fade out using css
// change the time in this setTimeout function so that is it triggered as soon as your animation ends, match it with the animation duration, and have it started like 20 milli seconds before your animation ends,
document.getElementById("loader").className = "fade-out-loader";
setTimeout(()=>{
//this will make sure the loader is not showed anymore, and your main content will popup
setLoader(false)
}, 60)
// match time of the loader out transition so the transition will be smooth
}
},[])
{!loading}?
<div>Main content</div>:
<div class = "loader-class" id = "loader">Loader element</div>
Your css class should look like (App.css)
.loader-class{
dispaly:visible;
}
.fade-out-loader{
//add an fade animation to this class, you can get them at Animista
}

Related

How to add a loading animation during the calculation in the Website?

I am making a website which performs some calculations and then plots a graph. Now what I want is when the computation is going on, it should show a loading animation and when the calculations are done, that animation should disappear.
P.S. It has nothing to do with page loading so I guess page loader is not an option.
document.getElementById("submitButton").onclick=function()
{
document.getElementById("loader").style.display='flex'; //this is the animation div
const permutationGeneration = (arr = []) => {
let res = []
const helper = (arr2) => {
if (arr2.length==arr.length)
return res.push(arr2)
for(let e of arr)
if (!arr2.includes(e))
helper([...arr2, e])
};
helper([])
delete result;
return;
};
var randArray=Array.from({length : size}, () => Math.floor(Math.random() * 100000));
timeReq = new Date().getTime();
permutationGeneration(randArray);
timeReq = ((new Date().getTime()) - timeReq)/1000;
}
This is the code snippet, now when permutation generation is going on, I want a loading animation.
When I click submit button, display changes from 'none' to 'flex'. Now how to change display back to none, when calculation is done & graph is plotted.
One way you can do it is with setTimeout which sets a timeout before something happens. For example, in this code down here, it loads and gif which is loading gif. After 2-3 seconds, the results go from display:none to display:block; and vice versa with the gif. It shows for 2 seconds, and after that timeout, it gets a style of display:none.
// Listen for submit
document.getElementById('loan-form').addEventListener('submit', function(e){
// Hide results
document.getElementById('results').style.display = 'none';
// Show loader
document.getElementById('loading').style.display = 'block';
setTimeout(calculateResults, 2000);
e.preventDefault();
});

Image loading in react "with refs" vs "with state"

What I want to do is, I've an Image component which shows some loading state as placeholder colour (via css background-colour) till image loads then swap it with the actual image.
Css
.show-img {
opacity: 1;
transition: all 0.3s ease-in;
}
.hide-img {
background-color:#eee;
opacity: 0;
transition: all 0.3s ease-in;
}
Using state
const Image = () => {
const [loading, setLoading] = useState(false);
const onImgLoad = () => {
setLoading(true);
};
return (
<img
src="https://i.picsum.photos/id/498/200/300.jpg"
className={loading ? 'hide-img' : 'show-img'}
onLoad={onImgLoad}
/>
);
};
Using refs
const Image = () => {
const ref = useRef();
const onImgLoad = (e) => {
//if img is loaded
if (e.target.src && ref.current) {
ref.current?.classList?.remove('hide-img');
ref.current?.classList?.add('show-img');
}
};
return (
<img
ref={ref}
src="https://i.picsum.photos/id/498/200/300.jpg"
className="hide-img"
onLoad={onImgLoad}
/>
);
};
I want to know which one of the approach is more performant and why? I was thinking about avoiding re-rendering due to state update for such a basic task (maybe).
PS: I've this Image component inside the carousel and there are multiple carousels on the page.
Thank you,
Theoretically speaking, I would argue that using state is more performant as the state is handled by react and its virtual DOM which is way faster than updating the DOM directly with useRef. Additionally, using state warranties the component re-rendering but optimised by react, which means only when its needed. I used the following articles to reach to this conclusion.
https://medium.com/swlh/useref-explained-76c1151658e8
https://blog.logrocket.com/usestate-vs-useref/
Nonetheless you may have to implement a profiler to check if this is true, as for the final user it may not look as the fastest solution, due to other circumstances outside react, like the amount of images, the connection speed and whether the images are in a CDN or not, just to mention some.

Make SearchBar dissappear when resizing manipulating DOM in script

I have a header with the main navigationBar and a searchBar that appears only on small devices when clicking on an icon. For activating the searchBar I have a hook called useBoolean that returns a searchBarisShown, openSearchBar, closeSearchBar, and toggleSearchBar.
I have a wrapper for both navigationBar and searchBar and for animation purposes for the shadow I have another wrapper. It looks like this.
const Header = () => {
// Hooks
const [isSearchShown, openSearchBar, closeSearchBar, toggleSearch] = useBoolean()
const topMenuAnimation = useSpring({
transform: isSearchShown ? `translateY(0)` : `translateY(-100%)`,
})
const headerHeightAnimation = useSpring({
// 99px = 48px from search bar + 51px from header
height: isSearchShown ? '99px' : '51px',
})
if (window.innerWidth >= '990px') {
closeSearchBar()
}
return (
<HeaderMainContainer style={headerHeightAnimation}>
<HeaderBar>
{content}
</HeaderBar>
<SearchBar style={topMenuAnimation}>
<SearchFieldBar />
</SearchBar>
</HeaderMainContainer>
)
}
The thing is I want to close my searchBar with closeSearchBar when resizing over 990px because otherwise, I have my shadow way down below my navigation bar when this is closed. If I try to do this on styled-components with a media query it doesn't work because I am using styled-components and this only manipulates the virtual DOM and useSpring manipulates de real DOM. Do you have any suggestions on how to make this searchBar disappear?

React: Trying to achieve a sequential fade-in effect with a Masonry layout but it's out of order

I been trying to make a Masonry gallery with a sequential fade-in effect so that the pictures fade in one by one. And there is also a shuffle feature which will randomize the images and they fade in again after being shuffled.
here is the demo and the code:
https://tuo1t.csb.app/
https://codesandbox.io/s/objective-swartz-tuo1t
When first visiting the page, the animation is correct. However once we click on the shuffle button, something weird happened: There are often some pictures don't fade-in sequentially after the image before them faded in, there is even no fade-in animation on them, they just show up out of order.
The way I achieved this animation is by adding a delay transition based on the index of the image, and use ref to track images.
first I initialize the ref
let refs = {};
for (let i = 0; i < images.length; i++) {
refs[i] = useRef(null);
}
and I render the gallery
<Mansory gap={"1em"} minWidth={minWidth}>
{imgs.map((img, i) => {
return (
<PicContainer
index={img.index}
selected={isSelected}
key={img.index}
>
<Enlarger
src={img.url}
index={img.index}
setIsSelected={setIsSelected}
onLoad={() => {
refs[i].current.toggleOpacity(1); <--- start with zero opacity images till those are loaded
}}
ref={refs[i]}
realIndex={i}
/>
</PicContainer>
);
})}
</Mansory>
for the every image component
class ZoomImg extends React.Component {
state = { zoomed: false, opacity: 0 };
toggleOpacity = o => {
console.log("here");
this.setState({ opacity: o }); <-- a setter function to change the opacity state via refs:
};
render() {
const {
realIndex,
index,
src,
enlargedSrc,
setIsSelected,
onLoad
} = this.props;
return (
<div style={{ margin: "0.25rem" }} onLoad={onLoad}>
<Image
style={{
opacity: this.state.opacity,
transition: "opacity 0.5s cubic-bezier(0.25,0.46,0.45,0.94)",
transitionDelay: `${realIndex * 0.1}s` <--- add a delay transition based on the index of the image.
}}
zoomed={this.state.zoomed}
src={src}
enlargedSrc={enlargedSrc}
onClick={() => {
this.setState({ zoomed: true });
setIsSelected(index);
}}
onRequestClose={() => {
this.setState({ zoomed: false });
setIsSelected(null);
}}
renderLoading={
<div
style={{
position: "absolute",
top: "50%",
color: "white",
left: "50%",
transform: "translateY(-50%} translateX(-50%)"
}}
>
Loading!
</div>
}
/>
</div>
);
}
}
I used console.log("here"); in the setter function, which will be called for changing the opacity state via refs. There are 16 images, so initially it is called 16 times. But when I clicked on the shuffle button, you can see that it is called fewer than 16 times because some of the pictures show up directly without fading in.
I been struggling with this problem for days and really hope someone can give me some hints.
The problem is that your are adding only some new images in the shuffle method, one approach is to apply 0 opacity to all refs first, then wait a few ms to add 1 opacity again, like here.
But, I would recommend a better approach for animation, I love shifty and its Tweenable module.

How do I (correctly) check whether an element is within the viewport in React?

In a functional react component, I'm trying to check whether a call to action button (a different component) is within the viewport. If it's not, I want to display a fixed call to action button at the bottom of the viewport, which shows/hides, depending on whether the other button is visible.
I can do this using a combination of Javascript and react hooks, but although the code works in some components in my app, it doesn't work in others; I'm guessing due to react lifecycles.
I'm also aware that this is NOT the way I should be doing things in react, so would prefer to achieve the same result, but in a proper 'react way'.
I've been looking at using refs, but ideally wanted to avoid having to change my functional component to a class, as I'd like to use react hooks for the show/hide of the fixed cta. However, if this is a requirement in order to get the functionality I want, I could go for that.
Here's what I've got so far - basically, I want to replace document.querySelector with a react method:
useEffect(() => {
const CTA = document.querySelector('#CTANextSteps');
const ApplyStyle = () => (isInViewport(CTA) ? setVisible(false) : setVisible(true));
ApplyStyle();
window.addEventListener('scroll', ApplyStyle);
window.addEventListener('resize', ApplyStyle);
return function cleanup() {
window.removeEventListener('scroll', ApplyStyle);
window.removeEventListener('resize', ApplyStyle);
};
});
const isInViewport = (elem) => {
const bounding = elem.getBoundingClientRect();
return (
bounding.top >= 0 &&
bounding.left >= 0 &&
bounding.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
bounding.right <= (window.innerWidth || document.documentElement.clientWidth)
);
};
As mentioned above, this function works in some areas of the app without issue, but doesn't in others; I get a Cannot read property 'getBoundingClientRect' of null error. I was surprised it worked at all, but rather than tinkering with it to try and get it working everywhere, I want to rewrite it properly.
As always, any assistance would be much appreciated. Thanks.
I was able to do it with the depedency react-visibility-sensor#5.1.1
I followed the tutorial in this link and it worked fine with me.
I don't know if this is the correct way to do it, but it works!
Here is the link https://www.digitalocean.com/community/tutorials/react-components-viewport-react-visibility-sensor
I'll put an example just in case the previous link ever goes out.
import React, { Component } from 'react';
import VisibilitySensor from 'react-visibility-sensor';
class VisibilitySensorImage extends Component {
state = {
visibility: false
}
render() {
return (
<VisibilitySensor
onChange={(isVisible) => {
this.setState({visibility: isVisible})
}}
>
<img
alt={this.props.alt}
src={this.props.src}
style={{
display: 'block',
maxWidth: '100%',
width: '100%',
height: 'auto',
opacity: this.state.visibility ? 1 : 0.25,
transition: 'opacity 500ms linear'
}}
/>
</VisibilitySensor>
);
}
}
export default VisibilitySensorImage;

Categories

Resources