I'm struggling with react-spring to fade out a loading screen and then unmount it.
The component unmounts but without animation and I can't figure why. I created a sandbox to illustrate:
https://codesandbox.io/s/nkxjxwo2xl
import React from 'react'
import ReactDOM from 'react-dom'
import { Transition } from 'react-spring'
class Loader extends React.PureComponent {
state = { loaded: false }
componentDidMount() {
setTimeout(() => {
this.setState({ loaded: true })
}, 1000)
}
render() {
const { percentage } = this.props
const styles = {
height: '100vh',
width: '100vw',
background: 'tomato'
}
return (
<Transition native from={{ opacity: 1 }} leave={{ opacity: 0 }}>
{!this.state.loaded &&
(style => (
<div style={Object.assign({}, styles, style)}>
<div>{Math.round(percentage)} %</div>
</div>
))}
</Transition>
)
}
}
ReactDOM.render(<Loader percentage={0} />, document.getElementById('root'))
There are no react-spring tags yet if anyone could create one, I think it would be helpful.
Yep, you fixed it yourself, the animated.div component was missing. I would recommend the use of it, though. Even if your view is small, it will still be rendered out 60 times per second by React otherwise (meaning it will go through all component phases 60 times + render). With native set it renders once and the animation will be applied in a requestAnimationFrame-loop directly in the dom (via instance.style.setProperty, it completely skips React - which makes a difference once your app gets bigger.
I found the solution if anyone finds this question.
Using the native attribute, you'll need to use animated.div (or any animated component) in order to have it animated. Or simply remove the native attribute. In my case, it is a loader which is not often displayed so I went for the easier way by simply removing the native attribute.
More info on the Spectrum react-spring community
Related
I'm having this weird issue where my styling is not sticking. I have a NavBar set to be 20vh in height. I also have an image set to be 100% in width. However, when I refresh the page, the NavBar height shrinks and the image width increases significantly. I'm not sure what is causing this problem. I have pasted the relevant code below but you can also find the repo for the app at this link (dev branch).
const useStyles = makeStyles((theme) => ({
navBar: {
height: "20vh",
width: "100%",
},
}));
const NavBar = () => {
const classes = useStyles();
return <div className={classes.navBar}>NavBar</div>;
};
const useStyles = makeStyles((theme) => ({
introImg: {
width: "100%",
height: "auto",
},
}));
const Intro = () => {
const classes = useStyles();
return <img src={marco4sup} className={classes.introImg} />;
};
As you can see, the NavBar is definitely not 20vh and the image is expanding beyond 100% of the page width.
Alert: I will give a pull request on the repo on github so you can implement the code. Fast Refresh is a Next.js feature that gives you instantaneous feedback on edits made to your React components. Fast Refresh is enabled by default in all Next.js applications on 9.4 or newer. With Next.js Fast Refresh enabled, most edits should be visible within a second, without losing component state.
How It Works
If you edit a file that only exports React component(s), Fast Refresh will update the code only for that file, and re-render your component. You can edit anything in that file, including styles, rendering logic, event handlers, or effects.
If you edit a file with exports that aren't React components, Fast Refresh will re-run both that file, and the other files importing it. So if both Button.js and Modal.js import theme.js, editing theme.js will update both components.
Finally, if you edit a file that's imported by files outside of the React tree, Fast Refresh will fall back to doing a full reload. You might have a file which renders a React component but also exports a value that is imported by a non-React component. For example, maybe your component also exports a constant, and a non-React utility file imports it. In that case, consider migrating the constant to a separate file and importing it into both files. This will re-enable Fast Refresh to work. Other cases can usually be solved in a similar way.
Arrow functions aren't supported. Name your functional component.
export default function MyPage () {...
Without export defualt function MyPage() {... it won't use fast refresh therefore your code won't work, to implement it into your Code do the following(for code block1):
export default function UseStyles () {
navBar: {
height: "20vh",
width: "100%",
},
}));
const NavBar = () => {
const classes = useStyles();
return <div className={classes.navBar}>NavBar</div>;
};
Sorry if there are any grammatical errors my english isn't great.
And also if you want your navbar to be sticky set the position to sticky like the following:
position: sticky;
I am trying to use a functional component and React hooks to implement a simplified auto-scroller that will automatically scroll a container to the bottom when the child content overflows. But the auto-scrolling should only happen when the scrollbar is already enar the bottom (e.g., if the user has scrolled up to look at output, the scroll position should not change when new content comes in).
I know how to implement the auto-scrolling behavior by using refs and performing computation on clientHeight, scrollTop, and scrollHeight.
The problem I have is that I need to compute a shouldAutoScroll() check BEFORE the component is re-rendered.
My flow needs to look like this:
<container>
{props.children}
</container>
When props.children changes:
1. Check if the scrollbar is near the bottom and store the result
2. Update container to reflect the new props.children
3. If the check from step 1 is true, scroll to the bottom
I can't seem to find a way to to this using useEffect and/or useLayoutEffec. When using these what happens is:
1. Scroll position is at bottom
2. props.children updates with new items
3. <container> is rerendered, pushing the scrollbar up
4. The checkScrollBarBottom() method is called and returns false
5. The scrollbar is not auto-scrolled
I need to keep the component generic, so that it can auto scroll regardless of what type of component or element props.children is. In some cases the change to props.chldren might be a single line. In others, it might be 20 lines, or it might be an image.
If I were using an older-style class component, I could do the computation in componentWillReceiveProps(). How do I replicate this with hooks?
I discovered one solution that works, but seems a little messy.
The solution is to calculate and update shouldAutoScroll() during the container's onScroll() event. This seems messy because I am capturing a ton of useless intermediate scroll information, when all I care about is the scroll position at the moment the update starts (but before the component is re-rendered).
Full code:
import React, { useRef, useEffect, useLayoutEffect } from 'react';
import styles from './AutoScroller.module.scss';
export function AutoScroller({children, className=''}) {
const classNames = `${styles.default} ${className}`;
const containerRef = useRef(null);
const shouldAutoScroll = useRef(false);
function updateShouldAutoScroll(element, tolerance) {
const {scrollHeight, scrollTop, clientHeight} = element;
const result = scrollHeight - scrollTop <= clientHeight + tolerance;
shouldAutoScroll.current = result;
}
function onContainerScroll(e) {
updateShouldAutoScroll(e.target, 25)
}
useEffect(function autoScroll() {
if (shouldAutoScroll.current) {
const element = containerRef.current;
element.scrollTop = element.scrollHeight;
}
});
return (
<div className={classNames} ref={containerRef} onScroll={onContainerScroll}>
{children}
</div>
)
}
I am wondering if it is possible to debounce a jsx element's rendering. I have an animation of a panel expanding that has some content in it. If the panel is empty (just the background) the animation is smooth and works as expected. The animation and associated components are all from Material-UI. The issue arises when the content is in the panel already so the animation (width expansion) just skips out to the width of the content making the animation look choppy. Here is a similar example to what I am referring to. This code is my code I am using in my panel and they work the same in terms of the expansion. Only difference is the content in this example is just lorem ipsum so the animation appears to work fine. Is it possible to debounce the <CardContent /> component's rendering like this?
{ open &&
(
_.debounce(e => {
return (
<CardContent>
{/*content in here*/}
</CardContent>
)
}, 300)
)
}
or something similar (this doesn't work) so the panel will be fully expanded through the animation before the content is rendered?
I'd like to add a comment however my reputation isn't above 50 yet so unfortunately I can't :p.
JS Animation
To answer your question, if you are using JavaScript animations like GSAP or AnimeJS you can have a state flag called. isAnimating = null. Then when your animation starts set the flag to true and when it's finished set it to false. Then in your render() method write a conditional render like this.state.isAnimating === false && <CardContent />.
CSS Animation
If you are using CSS animation you can use the transitionend event to wait for the animation to end. Therefore you have to create a ref on the animating DOM element to which you can attach the event.
Does that help you a bit? Please let me know if you have any other questions.
Here is a solution using react spring library
I added a state variable in order to display or not the card content
const [contentVisible, setContentVisible] = React.useState(false);
I created a spring to handle the width transition, I set contentVisible to true as soon as the width approaches the 300
const { width } = useSpring({
width: open ? 300 : 120,
onFrame: ({ width }) => setContentVisible(width > 299.8)
});
Finally, I created an animated card component
const AnimatedCard = animated(Card);
...
<AnimatedCard classes={{ root: classes.card }} style={{ width }}>
I'm using React TransitionGroup and Velocity to animate transitions between routes.
I'm trying to do a simple animation where the destination route component slides in from the left and the source route slide outs the right.
I have that animation running now, but they don't get aligned vertically. i.e. the new component gets added to the dom on top of the old one so we get what is in the screenshot below. This is when we navigate from Edit to Preview. The Form header is part of Edit and gets pushed to the bottom as Preview comes in.
Here is what the DOM looks like as the animation is running.
I'm sure I just need some css to achieve this, but not sure how to go about it.
example of Preview code:
import React from 'react';
import ReactDom from 'react-dom';
import Velocity from 'velocity-animate';
import 'velocity-animate/velocity.ui';
class Preview extends React.Component{
componentWillEnter(callback){
const el = ReactDom.findDOMNode(this);
if (!el) {
console.error('not el!', el);
}
Velocity(el, 'transition.slideLeftBigIn', {duration: 1000, complete: callback});
}
componentWillLeave (callback) {
const el = ReactDom.findDOMNode(this);
console.log('otw out')
Velocity(el, 'transition.slideRightBigOut', {duration: 1000, complete: callback});
}
render(){
return (
<div>
<h2>Preview</h2>
<img src=""/>
</div>
);
}
}
Transition Group defintion in App.jsx
<TransitionGroup>
{React.cloneElement(this.props.children, {
key: Math.random()
})}
</TransitionGroup>
Your instinct to solve this with CSS was right on. The cause is elements that have display: block and `position: static' will stack up vertically in source order (all other things equal).
https://jsfiddle.net/ez10xbrv/
You can change the animating components to have position: absolute and their container to have position: relative so they don't leave space for previous siblings. Note that if you go this route, your container (the <span> in your example) will not have any natural size so you may need to assign it a height and width. CSS Tricks has some good information on positioning that might help.
https://jsfiddle.net/ez10xbrv/1/
According to react documentation only way to animate is by usingReactCSSTransitionGroup. Is there anyway to do animation using only Javascript?
Thanks.
Typical way to do a fadeIn animation is:
define a css-class that animates fadeIn in someway
in componentDidMount(), add a setState() method that adds the faded-in class to your component
your component will then re-render, with the new class. Applying any css animations that you have defined (in css of course)
PS: With simple javascript, you can only add animation when the component appears, or when it updates.
When your component leaves (so if you would want a fade-out animation), it is much, much harder to do that with javascript only.
Finally i found this npm package It has all the basic animation.
for fadeIn animation
constructor(props) {
super(props);
this.state = {
opacity: 0
}
// react state animation wrapper
this._animate = new ReactStateAnimation(this)
}
componentDidMount () {
this._fadeIn();
}
_fadeIn = () => {
this._animate.linearIn('opacity', 0.9, 300);
};
pretty simple!