React切换类+ CSS转换,不起作用...为什么?

10

我一直在使用类来控制开/关行为,并使用CSS过渡效果。我在其他组件上使用过这个方法,没有问题,但出现在这种情况下失败的原因仍不清楚...

开/关行为附加(我看到背景颜色和translateY的最终差异),但是CSS过渡本身丢失了... 有什么想法吗?为什么我失去了CSS过渡,但其他所有东西都正常工作呢?

请注意,当我使用开发者工具手动切换“打开/关闭”类时,它可以正常工作!CSS过渡效果也能够实现!

那么,React在点击切换类时发生了什么?为什么会失去CSS过渡效果呢?

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看起来如下:

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;
    }
}

1
它必须完全替换DOM元素。当您打开DevTools并切换菜单时,整个DOM元素会闪烁,还是仅其class属性会闪烁? - Dan
我的赌注在Router库上。如果您不使用RouteRouter包装Projects,请尝试一下它是否有效?另外,您使用的是哪个react-router版本? - Jordan Enev
你的代码没有显示导入CSS过渡组吗?import { CSSTransitionGroup } from 'react-transition-group'.... 在转换和React方面存在一些问题(这就是为什么最初发布了该附加组件的原因)... 这里有一篇很好的文章链接 - Rachel Gallen
3个回答

12
这是因为react-router将每条路由视为switch语句中的一个case,而<Route />组件中的path是该case的key。当路径被更改时,组件会完全卸载。因此,您看不到CSS转换,因为它的DOM已不存在。
如果您想使用react-router进行动画处理, 您需要使用一个名为 react-transition-group 的React实用程序库。以下是react-router作者提供的详细示例,您可以参考。 React Router Animation Example 希望这有所帮助。
此外,在YouTube上还有一次约30分钟的精彩演讲,介绍如何在React中使用路由做出非常好的动画效果,链接为:https://www.youtube.com/watch?v=S3u-ccn4PEM,祝好 :)

4

实际上,问题在于react-router会卸载你的组件并再次挂载它,使用新的类,这个过程中会丢失CSS过渡效果。为了解决这个问题,只需在<Route>组件上使用render不是component

至于为什么这样可以解决问题,来自react-router文档:

您可以传递一个函数作为<Route>组件的component属性代替通过该属性为您创建一个新的React元素。当位置匹配时将调用这个函数。渲染prop接收与组件渲染prop相同的所有路由属性。

如果需要更详细的解释,可以阅读问题react router difference between component and render

简而言之,App.js应该如下所示:

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>
    }
}

我使用render创建了一个CodeSandbox,看起来它能够正常工作!祝你好运!

3

更改密钥必须更新元素。

尝试这段代码:

class App extends React.Component {
    constructor() {
        super();
        this.state = {
            _isProjectNavOpen: true,
            _ProjectsKey: 1,
            _RouteKey: 1
        }
        this._toggleProjectNav = this._toggleProjectNav.bind(this);
    }
    _toggleProjectNav() {
        this.setState(prevState => ({
            _isProjectNavOpen: !prevState._isProjectNavOpen,
            _ProjectsKey: prevState._ProjectsKey + 1,
            _RouteKey: prevState._RouteKey + 1
        }));
    }
    render() {
        <div>
            <Router>
                <Route key={this.state._RouteKey} path="/projects" component={(props, state, params) => 
                    <Projects 
                        _toggleProjectNav={this._toggleProjectNav}
                        _isProjectNavOpen={this.state._isProjectNavOpen} 
                        key={this.state._ProjectsKey} 
                    {...props} />} />
            </Router>
        </div>
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接