I've been using classes to control open/close behaviors w/ a CSS transition for effect. I've used this on other components, no problem, but for some reason the same method is failing me in this scenario...
The open/close behaviors attach (I see the end difference w/ background color and translateY) but the CSS transition itself is lost... any ideas why I lose my CSS transition but everything else is working as expected?
Note, when I manually toggle the open/closed classes using Developer Tools, it works just fine! The CSS transition picks up!
So what's up with the React on click to toggle a class applying, but losing the CSS transition?
class Projects extends React.Component {
/* constructor, etc... */
render() {
return (
<div className="projects-nav-container">
<div className="center title monospace" onClick={this.props._toggleProjectNav} id="Menu">Menu</div>
<ul className={`projects-nav ${this.props._isProjectNavOpen ? 'open' : 'closed'}`}>
{ PROJECTS.map((project, index) =>
<li key={index} >
<p>project here</p>
</li>
) }
</ul>
</div>
);
}
}
App.js looks as such:
class App extends React.Component {
constructor() {
super();
this.state = {
_isProjectNavOpen: true
}
this._toggleProjectNav = this._toggleProjectNav.bind(this);
}
_toggleProjectNav() {
this.setState(prevState => ({
_isProjectNavOpen: !prevState._isProjectNavOpen,
}));
}
render() {
<div>
<Router>
<Route path="/projects" component={(props, state, params) =>
<Projects
_toggleProjectNav={this._toggleProjectNav}
_isProjectNavOpen={this.state._isProjectNavOpen}
{...props} />} />
</Router>
</div>
}
}
SCSS:
.projects-nav {
@include transition(all $transition_speed ease);
&.open {
@include transform(translateY(0));
background: red
}
&.closed {
@include transform(translateY(-100vh));
background: green;
}
}
CSSTransition example: Transition a React component using CSS. The CSSTransition component allows you to apply transitions to elements entering and leaving the DOM using CSS. You can achieve this by using the following props: in , a Boolean value used to control the appearance of the element.
To trigger an element's transition, toggle a class name on that element that triggers it. To pause an element's transition, use getComputedStyle and getPropertyValue at the point in the transition you want to pause it. Then set those CSS properties of that element equal to those values you just got.
CSS transitions let you decide which properties to animate (by listing them explicitly), when the animation will start (by setting a delay), how long the transition will last (by setting a duration), and how the transition will run (by defining a timing function, e.g., linearly or quick at the beginning, slow at the ...
Indeed, the problem is that react-router
is unmounting your component and mounting it again with the new classes, losing the CSS transition in the process. To solve this issue, simply use render
instead of component
on the <Route>
component.
As to why this works, from react-router
documentation:
Instead of having a new React element created for you using the component prop, you can pass in a function to be called when the location matches. The render prop receives all the same route props as the component render prop.
For a more detailed explanation, you could read the question react router difference between component and render.
In summary, App.js should look like this:
class App extends React.Component {
constructor() {
super();
this.state = {
_isProjectNavOpen: true
}
this._toggleProjectNav = this._toggleProjectNav.bind(this);
}
_toggleProjectNav() {
this.setState(prevState => ({
_isProjectNavOpen: !prevState._isProjectNavOpen,
}));
}
render() {
<div>
<Router>
<Route path="/projects" render={(props, state, params) =>
<Projects
_toggleProjectNav={this._toggleProjectNav}
_isProjectNavOpen={this.state._isProjectNavOpen}
{...props} />} />
</Router>
</div>
}
}
I created a CodeSandbox using render
and it seems to work properly!
Cheers!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With