The problem is I have a form whit three states: default, error and success. Depending on the state, a specific component is rendered into the dom.
I need to add a fade in out animation when this component enters or leave.
I've tried whith custom CSS, GSAP ( but don't want to install more packages to my project ) and now trying with react-transition-group.
To keep is simple I've created the "error" component as follow:
export default class NewsletterFormError extends React.Component {
componentWillMount() {
}
componentDidMount() {
}
render() {
return (
<div className="NewsletterFormError">
I'm an error message
<style jsx>{`
.NewsletterFormError {
font-size: 50px;
}
`}</style>
</div>
)
}
}
And on the index page I have:
{ this.state.formError &&
<CSSTransitionGroup
transitionName="test"
transitionAppear={true}
transitionAppearTimeout={200}
transitionEnter={true}
transitionEnterTimeout={2000}
transitionLeave={true}
transitionLeaveTimeout={2000}>
<NewsletterFormError />
</CSSTransitionGroup>
}
For some reson, when this.state.formError is true, the component renders and the fade in is done, but when the state chages to false, the fade out is not working.
Unfortunately, pure React CSS Transition groups can't trigger an animation when a component is unmounted. See this github issue for more details. This repo with a comparison of animation methods in react may be helpful, they recommend using React CSS Transition groups in conjunction with GSAP or Anime.js
Related
I'm sure this is going to be a very straight forward answer, but I can't for the life of me work out how to get my Gatsby/React site to start at the top of a new page without a scroll transition effect when I click on an internal link.
Example:
On my home page I scroll to the bottom, then click on a link to take me to an 'About Me' page. The About Me Page loads with the browser scroll position still at the bottom of the page and then the window scrolls to the top of the page. This only takes a few milliseconds but when I click on a link I want to start at the top of the page without any transition.
The links are all standard Gatsby Links:
<Link className="" to="/aboutme/">
About Me
</Link>
Thanks!
EDIT
Adding in my layout wrapper, with useScrollRestoration hooks added:
import React from 'react'
import PropTypes from 'prop-types'
import useScrollRestoration from 'gatsby'
import NavBar from './NavBar/NavBar'
import Footer from './Footer/Footer'
import './layout.scss'
const Layout = ({ children }) => {
const aboutMeScrollRestoration = useScrollRestoration(`page-component-main`)
return (
<>
<NavBar />
<main className="bumpdown" {...aboutMeScrollRestoration}>
{children}
</main>
<Footer />
</>
)
}
Layout.propTypes = {
children: PropTypes.node.isRequired,
}
export default Layout
I managed to work this out in the end after a lot of Googling. It appears not to be a scrollRestoration issue but a Bootstrap issue. In bootstrap/scss/_reboot.scss there's the following code:
:root {
font-size: $font-size-root;
#if $enable-smooth-scroll {
#media (prefers-reduced-motion: no-preference) {
scroll-behavior: smooth;
}
}
}
This can be turned off either using $enable-reduced-motion: true; or $enable-smooth-scroll: false; in bootstrap overrides which stops the scrolling behaviour when a new page opens.
I'm using the enable-smooth-scrolling:false option as the other option may have further knock on effects.
I created a custom.scss file and imported it into the gatsby-browser.js file. The contents of the scss file is overriding the default value of the scroll-behaviour in bootstrap:
$enable-smooth-scroll: false;
:root {
scroll-behavior: auto !important;
}
#import "node_modules/bootstrap/scss/bootstrap";
This issue is known as Scroll Restoration. #reach/router (from where Gatsby extends its routing) handles it automatically. However, in some cases, it fails, especially when rendering containers that have their own scroll values. To bypass this "issue", Gatsby exposes a useScrollRestoration hook to restore the scroll position. For example:
import { useScrollRestoration } from "gatsby"
import countryList from "../utils/country-list"
export default function PageComponent() {
const ulScrollRestoration = useScrollRestoration(`page-component-ul-list`)
return (
<ul style={{ height: 200, overflow: `auto` }} {...ulScrollRestoration}>
{countryList.map(country => (
<li>{country}</li>
))}
</ul>
)
}
So, in your destination component (/aboutme/ page), use the useScrollRestoration hook in your outer wrapper to restore the scroll position.
Here's my slideshow.jsx file.I am trying to apply transition to a sample div containing Sample Text,but no transitions happening.
import React, { Component } from 'react';<br>
import styles from '../stylesheets/style.module.css';
import { CSSTransition, TransitionGroup } from 'react-transition-group';
class SlideShow extends Component {
state = {
backgroundColor: 'white',
changePic: true,
slideIndex: 1,
};
render() {
console.log(this.state.changePic);
return (
<div className={styles.slideshowContainer}>
<CSSTransition
in={this.state.changePic}
timeout={2000}
classNames={styles.slidePics}
mountOnEnter={true}
>
<div>
<p>sample text</p>
</div>
</CSSTransition>
</div>
);
}
}
export default SlideShow;
Here is my style.module.css file.Following properties associated with slidePics are below.But these transitions are not working:-
.slidePics-enter {
opacity: 0;
}
.slidePics-enter-active {
opacity: 1;
transition: opacity 2000ms;
}
the issue is you dont have a class slidePics at your css modules to be mapped to styles. if you add an empty rule .slidePics { } solves the issue.
other viable approach, you could map your transictions as:
classNames={{
enter: styles['slidePics-enter'],
enterActive: styles['slidePics-enter-active'],
}}
update
you already have in prop as true, given initial state. in initial state needs to be false and then with some iteraction you would change to true with the classes enter enter-active.
by your code, you would like to perform transition on mount state but as the docs says css transition wont perform enter transition by default on first mount.
for that to happen, you need to pass appear={true} and in={true}. likewise create the classes .slidePics-appear .slidePics-appear-active like you have for enter classes.
I'm building a React app that takes in a lot of data from temperature sensors at several different places and displays the data with chart.js.
I have made one component that fetch data from one place and that component is called from App.js, so now I could copy this component / or fetch data from another place if I implement it that way.
Next step is to find a way to swipe through these components. I don't know what to use or how I would go about to solve this, so I'm looking for ideas on how to solve this.
I have tried using react-swipeable-views. Code is provided in this post. This seems to be a simple solution, but I'm not sure if it's a good idea to do like this. I guess it would be quite heavy with large data sets? If I understand the way React works it would pull in data from all components to a browser and then hide it until it's showed?
I have also looked at this article: https://coursework.vschool.io/react-transitions-with-react-transition-group/
Here react-transition-group is used, but I'm not sure on how to implement the swipe part here since that is not discussed in the article.
Any ideas on how to solve this?
import React, {Component} from 'react';
import Test from './Test';
import SwipeableViews from 'react-swipeable-views';
const styles = {
slide: {
padding: 15,
minHeight: 800,
color: '#fff',
},
slide1: {
background: '#FEA900',
},
slide2: {
background: '#B3DC4A',
},
slide3: {
background: '#6AC0FF',
},
};
class App extends React.Component{
constructor(){
super();
this.state={
foo: 'bar'
}
}
}
render(){
return(
<div className="App">
<SwipeableViews enableMouseEvents>
<div style={Object.assign({}, styles.slide, styles.slide1)}>
slide n°1
<Test /> // <-- This would be a component with large data sets
</div>
<div style={Object.assign({}, styles.slide, styles.slide2)}>
slide n°2
</div>
<div style={Object.assign({}, styles.slide, styles.slide3)}>
slide n°3
</div>
</SwipeableViews>
</div>
)
}
export default App;
I have not used it before but looking at the docs, using react-swipeable-views should be fine, since it "quickly renders the first slide, then lazy-loads the others." (from https://github.com/oliviertassinari/react-swipeable-views). Furthermore you can customize how many slides before and after the currently displayed one are being rendered (see https://react-swipeable-views.com/api/api/#virtualize).
Also, it might be a good idea, to catch up on some react concepts (https://reactjs.org/docs/introducing-jsx.html). React does not "hide" any components, it only renders the ones you choose to the DOM and updates what is necessary to get the DOM to reflect your state. So for example, if you have multiple pages (p1, p2, p3), each rendering one component (c1, c2, c3), while being on page p1, only the component c1 would be rendered to the DOM.
I have a simple React Select as content prop in a Semantic UI React Popover component. I am constrained by each of the package versions inside the project (available in the following codesandbox https://codesandbox.io/s/wy194rz908):
React: ~15.5.0
ReactDOM: ~15.5.0
React-Select: ^2.1.1
Semantic UI React: 0.71.5
As you can see, the React Select options closes when a selection is done.
On the other hand, I found that updating React, React-DOM and SemanticUI to their latest versions make the feature work. As you can see, the selection is done and the Select options do not fold (available in the following codesandbox https://codesandbox.io/s/6y14qyykk3).
As I can not update update the React and SUIR, what workaround should I follow in order to make this work?
Thanks!
You have to use a Controlled Popup Component, as stated in docs:
import React from 'react'
import { Button, Popup } from 'semantic-ui-react'
class PopupExampleContextControlled extends React.Component {
state = {}
toggle = () => this.setState({ open: !this.state.open })
handleRef = node => this.setState({ node })
render() {
const { node, open } = this.state
return (
<div>
<Button content='Open controlled Popup' onClick={this.toggle} />
<Popup context={node} content='Hello' position='top center' open={open} />
---------->
<strong ref={this.handleRef}>here</strong>
</div>
)
}
}
export default PopupExampleContextControlled
In this way you can control when popup opens and closes.
I am controlling the Popup using the open prop available through its props api. I change its state from true to false when clicking the caret down icon button.
Solution: https://codesandbox.io/s/rmoxx98qkn
I have been reading about React Transition Group. 95% of the material talks about CSSTransitionGroup. My understanding is that CSSTransitionGroup just builds off of TransitionGroup which simply provides callback methods that correspond to various animation events.
So I've wrapped my component up in a TransitionGroup element and given it an animation event but it is never fired.
import React, { Component } from "react";
import { TransitionGroup, Transition } from "react-transition-group";
class Test extends Component {
componentWillAppear(cb) {
console.log('componentWillAppear')
cb()
}
render() {
return <div> test </div>
}
}
class App extends Component {
render() {
return (
<TransitionGroup>
<Test />
</TransitionGroup>
)
}
}
export default App;
You can use Transition or CSSTransition without TransitionGroup, but you can't use TransitionGroup without one of the others.
From the react-transition-group docs:
The <TransitionGroup> component manages a set of <Transition> components in a list. Like with the <Transition> component, <TransitionGroup>, is a state machine for managing the mounting and unmounting of components over time.
...As items are removed or added to the TodoList the in prop is toggled automatically by the <TransitionGroup>.
Try changing your Test component's render to something like this:
render() {
return (
<Transition timeout={150}>
{(status) => (
<div className={`fade fade-${status}`}>
test
<div>
)}
</Transition>
)
}