I'm trying to get my sidebar to slide in by toggling the state of my Sidebar (going from open: false to open: true) on component load. I'm doing this is an attempt to get a slide-in effect once the user loads the page.
Unfortunately, the way I'm currently doing this, it appears as though the state is changed and the component re-rendered essentially immediately, preventing the slide-in effect from happening. Here's my code:
export default class Sidebar extends React.Component {
constructor(props) {
super(props);
this.state = {open: false};
}
componentDidMount() {
this.setState({open: !this.state.open})
}
handleToggle = () => this.setState({open: !this.state.open});
render() {
return (
<div>
<Drawer width={'25%'} open={this.state.open}>
<AppBar title="Wealth Management" onLeftIconButtonClick={this.handleToggle}/>
<MenuItem>Menu Item</MenuItem>
<MenuItem>Menu Item 2</MenuItem>
</Drawer>
</div>
);
}
}
How do you get this to work? Am I updating on the wrong lifecycle method?
It is called CSS transition.
You could have a look at this medium post or check the MDN documentation.
We use a sidebar that slide open or closed based on user settings, the trick is to set a negative margin on the base css-class "sidebar" in this case.
Then add/remove the toggle class (on render or button event). That is all that is required to get a smoth animation on load
css-classes:
.sidebar {
z-index: 1000;
position: fixed;
left: 200px;
top: 0px;
bottom: 0px;
width: 250px;
margin-left: -250px;
-webkit-transition: all 0.5s ease;
-moz-transition: all 0.5s ease;
-o-transition: all 0.5s ease;
transition: all 0.5s ease;
}
.sidebarToggled {
width: 65px;
}
Related
I trying animate a component when rendering and unmount it in React, but unsuccessfully.
Component to animate
One of the ways I've tried was create a state (fade) with the class of animation property, when rendering, the class is fadeIn and on will unmount the class is fadeOut
const handlePokemonDetails = async () => {
if (pokemonDetails === true){
setFade(styles.fadeOut)
await timeout(500)
}
else{
setFade(styles.fadeIn)
}
setPokemonDetails(!pokemonDetails)
}
...
<div className={pokemonDetails ? styles.pokemonDetails + " " + fade : ""}></div>
SASS code:
.pokemonDetails
position: absolute
top: 0
z-index: 3
display: flex
width: 35vmin
height: 39.5vmin
flex-direction: column
background-color: rgba(210, 210, 210, 0.85)
border-radius: 10px
#keyframes fade
0%
height: 0vmin
100%
height: 39.5vmin
.fadeIn
animation: fade 0.5s normal
.fadeOut
animation: fade 0.5s reverse
But, when I change state to other class, the component don't apply this new class animation style. Does anyone know how I can fix this or another way to do it?
Good question. I just finished writing hook for React that helps with that
look at https://github.com/perymimon/React-Anime-Manager
Just publish ver2-alpha so the documentation is still lake.
import {useAnimeManager,ADDED,REMOVED} from "#perymimon/react-anime-manager"
const phase2class = {
[ADDED]: "fadeIn",
[REMOVED]: "fadeOut",
}
function Pokemons({pokemones}){
const pokemonesStates = useAnimeManager(pokemones);
return (
<pokemones>
{ pokemonesStates.map(state =>(
<div className={phase2class[state.phase] } onAnimationEnd={state.done}/>
)
)}
</pokemones>
)
}
This is the exact use case for react-transition-group.
Wrap your component inside <CSSTransition>
function App() {
const [inProp, setInProp] = useState(false);
return (
<div>
<CSSTransition in={inProp} timeout={200} classNames="my-node">
<div>
{"I'll receive my-node-* classes"}
</div>
</CSSTransition>
<button type="button" onClick={() => setInProp(true)}>
Click to Enter
</button>
</div>
);
}
Then add CSS to your classes. If you set className of CSSTransition to my-node, you will have 4 classes to style:
.my-node-enter {
opacity: 0;
}
.my-node-enter-active {
opacity: 1;
transition: opacity 200ms;
}
.my-node-exit {
opacity: 1;
}
.my-node-exit-active {
opacity: 0;
transition: opacity 200ms;
}
I have a div with adding a class by condition
<div
className={`${
showLinks ? "links-container show-container" : "links-container"
}`}
>
And some styles
.links-container {
height: 0;
overflow: hidden;
transition: all 0.3s linear;
}
.show-container {
height: 10rem;
}
So when the component is render/rerender, a smooth div extension animation is triggered thanks to my transition style. How it works? Is this css or react rules?
I'm trying to use the same button to open and close a menu, I'm sure this is super simple but I'm new to the world of jQuery. I'm using the Wordpress builder 'Oxygen' if that helps. Here's my code:
The modal is an in-built feature in the website builder so I can't provide much code on that. It's basically set to trigger when element with class "open" is clicked, and close with element class "oxy-modal-close".
jQuery
jQuery("#toggle").click(function () {
jQuery('#plus').toggleClass('rotate');
jQuery('#toggle').toggleClass('open oxy-modal-close');
});
HTML
<div id="toggle" class="open">
<img id="plus" src="http://hausse.co.uk/wp-content/uploads/2021/01/plus.svg"/>
</div>
CSS
#plus {
-moz-transition: transform 1s;
-webkit-transition: transform 1s;
transition: transform 0.3s;
width: 35px;
position: fixed;
top: 20px;
right: 20px;
}
.rotate {
transform: rotate(45deg);
}
Basically on the 2nd click, the class is re-adding the class "open", which is causing the menu to flicker as the two actions are conflicting with each other. Video here - https://gph.is/g/ZnNQddo
I have tried adding a delay to the class "open", but for some reason the delay is only working on the first click - on the second it's changing class instantly. This is the code I'm trying for that.
jQuery("#toggle").click(function () {
jQuery('#plus').toggleClass('rotate');
jQuery('#toggle').toggleClass('oxy-modal-close');
var el = jQuery("#toggle");
window.setTimeout(function() {
el.toggleClass('open');
}, 500);
});
You are referencing the id again within the click - you need to reference $(this)... to toggle the class on the click
Also - you need to start with one of the states - that way it can toggle the class to the other state on each click as per the snippet (the cross icon is on the right of the snippet widow as per styling ) - now when you click it rotates as intended.
$("#toggle").click(function() {
$('#plus').toggleClass('rotate');
$(this).toggleClass('open oxy-modal-close');
});
#plus {
-moz-transition: transform 1s;
-webkit-transition: transform 1s;
transition: transform 0.3s;
width: 35px;
position: fixed;
top: 20px;
right: 20px;
}
.rotate {
transform: rotate(45deg);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="toggle" class="open">
<img id="plus" src="http://hausse.co.uk/wp-content/uploads/2021/01/plus.svg"/>
</div>
i m using reactjs and i have a datepicker component that i hide when the user clicks outside of the component element.
the code snippet is like so:
`
class DatePicker extends Component{
constructor(props){
super(props)
state= { focus: false } // when focus: false i hide the dates component
}
.......
render(){
const { focus } = this.state
return(
<input type="text" placeholder="start date">
<input type="text" placeholder="start date">
{focus && <DatesContainer ...props>} // if focus==false i dont show the <DatesContainer> component.I need to hide it with fade out or something.
)
}
}`
So when the user clicks outside of the <DatesContainer/> the state.focus updates to false, the re-renders and, this time, the <DatesContainer/> is not render at all, so far so good. But i need to hide it with a 0.3s animation.
Any opinions on that ?
The difference between my answer and previous is you're able to set specific actions to certain animation keyframes.
The key point is to provide animation name as a function parameter
CSS
.Modal {
position: fixed;
top: 30%;
left: 25%;
transition: all 0.3s ease-out;
}
.ModalOpen {
animation: openModal 0.4s ease-out forwards;
}
.ModalClosed {
animation: closeModal 0.4s ease-out forwards;
}
#keyframes openModal {
0% { transform: translateY(-100%); }
100% { transform: translateY(0); }
}
#keyframes closeModal {
0% { transform: translateY(0); }
100% { transform: translateY(-100%);}
}
JS
const modal = ({
isShown, isMounted,
initiateUnmountAction, unmountAction
}) => {
const cssClasses = [
"Modal",
props.isShown ? "ModalOpen" : "ModalClosed"
];
return (
<Fragment>
{isMounted && <div className={cssClasses.join(' ')}
onAnimationEnd={event =>
{event.animationName == "closeModal" && unmountAction}
}>
<h1>A Modal</h1>
<button className="Button" onClick={initiateUnmountAction}>
Dismiss
</button>
</div>}
</Fragment>
);
};
I'd update the state to have a transitioning property. Using CSS animations or transitions, and some conditional rendering, we can apply a new class to the DatesContainer, detect when an animation is finished and change the focus state to false.
You'll have to set transitioning to true in the state whenever you click outside it.
It may look something like this:
CSS
#keyframes fadeOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
.fading {
animation-name: fadeOut;
animation-duration: 0.3s;
animation-fill-mode: forwards;
will-change: opacity;
}
JS
//import your styles here
class DatePicker extends Component{
constructor(props){
super(props)
state= { focus: false, transitioning: false }
}
handleFade() {
this.setState({transitioning: false})
}
render(){
const { focus, transitioning } = this.state
return(
<input type="text" placeholder="start date">
<input type="text" placeholder="start date">
{focus && <DatesContainer
className={transitioning === true ? "fading" : null}
onAnimationEnd={transitioning === true ? () => this.handleFade() : null}
/>
}
)
}
}`
I'd like to accomplish the following with my drop down menu.
1 - Show it upon click
2 -Hide it on second click
3 - Hide it when clicking anywhere outside of it.
4 - Do all that with a slide effect
I've got 1-3 covered. I'm blocked on 4.
How would I create a slide effect along with the following click event happening bellow?
I've got a working proof of concept using jQuery's slideToggle (not shown here)... however, I'd like to learn how to do it in the react way.
in case you'd like to see the full the code:
react drop-down nav bar
// CASE 1 Show Hide on click, no slide effect yet
class ServicesDropdown extends Component {
constructor() {
super();
this.state = {
dropdown: false
};
}
handleClick = () => {
if (!this.state.dropdown) {
// attach/remove event handler
document.addEventListener('click', this.handleOutsideClick, false);
} else {
document.removeEventListener('click', this.handleOutsideClick, false);
}
this.setState(prevState => ({
dropdown: !prevState.dropdown,
}));
}
handleOutsideClick = (e) => {
// ignore clicks on the component itself
if (this.node.contains(e.target)) {
return;
}
this.handleClick();
}
render() {
return (
<li ref={node => { this.node = node; }}>
<a href="#!" onClick={this.handleClick}>Services +</a>
{this.state.dropdown &&
(
<ul className="nav-dropdown" ref={node => { this.node = node; }}>
<li>Web Design</li>
<li>Web Development</li>
<li>Graphic Design</li>
</ul>
)}
</li>
)
}
}
A while ago I figured out how to apply a slide-down effect to a React component, it's not exactly the same behavior but you might find my code & description useful. See my answer to a different, related question here: https://stackoverflow.com/a/48743317/1216245 [Edit: It was deleted since then, so I'm pasting the description below.]
The blog post is here: http://blog.lunarlogic.io/2018/slidedown-menu-in-react/. Feel free to steal any part of the code.
Here's a short description of the most important parts of the solution.
As for the React/JSX part, you wrap the component that you'd like to slide in a CSSTransitionGroup. (You can read more about this React Add-on here: https://reactjs.org/docs/animation.html#high-level-api-reactcsstransitiongroup and here: https://reactcommunity.org/react-transition-group/.)
<div className="component-container">
<CSSTransitionGroup
transitionName="slide"
transitionEnterTimeout={300}
transitionLeaveTimeout={300}
>
{ this.state.showComponent && <Component /> }
</CSSTransitionGroup>
</div>
Note that it's all wrapped in a container, which you'll need for the animation to work like you'd like it to.
And here is the CSS I used for the slide animation effect:
/*
Slide animation styles.
You may need to add vendor prefixes for transform depending on your desired browser support.
*/
.slide-enter {
transform: translateY(-100%);
transition: .3s cubic-bezier(0, 1, 0.5, 1);
&.slide-enter-active {
transform: translateY(0%);
}
}
.slide-leave {
transform: translateY(0%);
transition: .3s ease-in-out;
&.slide-leave-active {
transform: translateY(-100%);
}
}
/*
CSS for the submenu container needed to adjust the behavior to our needs.
Try commenting out this part to see how the animation looks without the container involved.
*/
.component-container {
height: $component-height; // set to the width of your component or a higher approximation if it's not fixed
min-width: $component-width; // set to the width of your component or a higher approximation if it's not fixed
}
For the full example & demo check out http://blog.lunarlogic.io/2018/slidedown-menu-in-react/.
What aboot using CSS transitions?
UI Animations with React — The Right Way
As an example I found this slide effect that could be implemented on your navbar.
.wrapper {
position: relative;
overflow: hidden;
width: 100px;
height: 100px;
border: 1px solid black;
}
#slide {
position: absolute;
left: -100px;
width: 100px;
height: 100px;
background: blue;
-webkit-animation: slide 0.5s forwards;
-webkit-animation-delay: 2s;
animation: slide 0.5s forwards;
animation-delay: 2s;
}
#-webkit-keyframes slide {
100% { left: 0; }
}
#keyframes slide {
100% { left: 0; }
}
<div class="wrapper">
<img id="slide" src="https://cdn.xl.thumbs.canstockphoto.com/-drawings_csp14518596.jpg" />
</div>
I hope it helps :)