反应 CSSTransition 错误 class 在退出时使用

React CSSTransition wrong class used on exit

更新:

对于那些面临相同问题的人:我在 ReactTransitionGroup 的 git 页面上发现了一个类似的问题,其中包含解决方案:https://github.com/reactjs/react-transition-group/issues/182.

老实说,90% 的解决方案都让我大吃一惊,我根本不了解其中的大部分内容,这是对我来说唯一有意义的部分(摘自 与 git 问题相关联):

Passing Props to Leaving Children? Now the question is, why aren't updated props being passed to the leaving element? Well, how would it receive props? Props are passed from a parent component to a child component. If you look at the example JSX above, you can see that the leaving element is in a detached state. It has no parent and it is only rendered because the is storing it in its state.

我必须进一步研究和了解父子组件的通信方式。我对 Web 开发还是个新手,但事情正在慢慢开始变得有意义。

--------------------

最初提出的问题:

当您尝试将状态注入到您通过 React.cloneElement 的子项时,离开组件不是这些子项之一。

我有一个小应用程序,其中包含嵌套在切换容器之间的导航菜单和路由。每次点击导航项,我都会检查索引是更高还是更低,以相应地设置动画状态(左或右),然后存储被点击的导航项的新索引。

每次我切换路线时,应用的动画要么是向左淡入淡出,要么是向右淡入淡出。现在一切正常,但唯一的问题是当 class 从左侧切换到右侧时,应用的 EXIT 动画使用之前给定的 class。

我明白为什么会这样,因为使用的出口 class 是最初设置的,当新的 class 仅应用于第二次更改时,新出口是否生效.转换文档非常有限,我找不到任何东西。

const { Component } = React;
const { TransitionGroup, CSSTransition } = ReactTransitionGroup;
const { HashRouter, Route, NavLink, Switch, withRouter } = ReactRouterDOM;

var icons = [
 {icon: 'far fa-address-book active', path: '/'},
 {icon: 'fab fa-linkedin', path: '/linked'},
 {icon: 'fas fa-gamepad', path: '/hobbies'}
];

const Nav = props => {
  return (
   <div className="nav">
    <ul>
      { 
        icons.map((icon, index) => {
          return (
            <li
              key={index}
              onClick={() => props.clicked(index)}
              className={props.active == index ? 'active' : false}>
                <NavLink to={icon.path} className="NavLink">
                  <i className={icon.icon} key={icon.icon}></i>
                </NavLink>
            </li>
          );
        })
      }
    </ul>
  </div>
);
}

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      currentViewIndex: 0,
      animationDirection: 'right'
    }

   this.setIndex = this.setIndex.bind(this);
 }

 setIndex(index){
   const animationDirection = index < this.state.currentViewIndex ? 'left' : 'right';
   this.setState({currentViewIndex: index, animationDirection});
 }

  render () {
    const { location } = this.props;

    return (
      <div className="container">
        <Nav active={this.state.currentViewIndex} clicked={() => this.setIndex()} />
        <TransitionGroup>
          <CSSTransition
            key={location.pathname}
            classNames={`fade-${this.state.animationDirection}`}
            timeout={1000}>
            <Switch location={location}>
              <Route exact path="/" render={() => <h1>Home</h2>} />
              <Route path="/linked" render={() => <h1>Linked</h2>} />
              <Route path="/hobbies" render={() => <h1>Hobbies</h2>} />
            </Switch>
          </CSSTransition>
        </TransitionGroup>
      </div>
    );
   }
 }

const AppWithRouter = withRouter(App);

ReactDOM.render(<HashRouter><AppWithRouter /></HashRouter>, document.querySelector('#root'));

应用于转换的 CSS classes:

.fade-left-enter {
  position: unset;
  transform: translateX(-320px);
}

.fade-left-enter.fade-left-enter-active {
  position: unset;
  transform: translateX(0);
  transition: transform .5s ease-in;
}

.fade-left-exit {
  position: absolute;
  bottom: 0;
  transform: translateX(0);
}

.fade-left-exit.fade-left-exit-active {
  transform: translateX(320px);
  transition: transform .5s ease-in;
}

.fade-right-enter {
  position: unset;
  transform: translateX(320px);
} 

.fade-right-enter.fade-right-enter-active {
  position: unset;
  transform: translateX(0);
  transition: transform .5s ease-in;
}

.fade-right-exit {
  position: absolute;
  bottom: 0;
  transform: translateX(0);
}

.fade-right-exit.fade-right-exit-active {
  transform: translateX(-320px);
  transition: transform .5s ease-in;
}

您的问题的原因是 退出组件已经分离 因此没有得到任何更新。您可以找到对您的问题的很好的解释

您可以使用 <TransitionGroup> 中的道具 childFactory 来解决这个问题:

childFactory

You may need to apply reactive updates to a child as it is exiting. This is generally done by using cloneElement however in the case of an exiting child the element has already been removed and not accessible to the consumer.

If you do need to update a child as it leaves you can provide a childFactory to wrap every child, even the ones that are leaving.

尝试在渲染方法中更改以下代码:

render () {
  const { location } = this.props;

  const classNames = `fade-${this.state.animationDirection}`; // <- change here

  return (
    <div className="container">
      <Nav active={this.state.currentViewIndex} clicked={() => this.setIndex()} />
      <TransitionGroup 
        childFactory={child => React.cloneElement(child, { classNames })} // <- change here
      >
        <CSSTransition
          key={location.pathname}
          classNames={classNames} // <- change here
          timeout={1000}
        >
            <Switch location={location}>
              <Route exact path="/" render={() => <h1>Home</h2>} />
              <Route path="/linked" render={() => <h1>Linked</h2>} />
              <Route path="/hobbies" render={() => <h1>Hobbies</h2>} />
            </Switch>
        </CSSTransition>
      </TransitionGroup>
    </div>
  );

}