Реагировать на неправильный класс CSSTransition, используемый при выходе
ОБНОВИТЬ:
Для тех, кто сталкивается с той же проблемой: я нашел похожую проблему, размещенную на git-странице ReactTransitionGroup с решением там: https://github.com/reactjs/react-transition-group/issues/182.
Честно говоря, 90% решений взорвалось прямо у меня над головой, и я совсем ничего не понимаю, это единственная часть, которая имела для меня смысл (взято из React TransitionGroup и React.cloneElement не отправлять обновленные реквизиты с которой связан вопрос git):
Передача реквизита оставляющим детям? Теперь вопрос в том, почему обновленные реквизиты не передаются уходящему элементу? Ну, как бы он получил реквизит? Реквизиты передаются от родительского компонента к дочернему компоненту. Если вы посмотрите на пример JSX выше, вы увидите, что выходящий элемент находится в отсоединенном состоянии. У него нет родителя, и он отображается только потому, что хранит его в своем состоянии.
Я должен продолжить исследование и понять, как родительский и дочерний компоненты взаимодействуют. Я все еще новичок в веб-разработке, но все постепенно начинает обретать смысл.
------------------
Начальный вопрос задан:
Когда вы пытаетесь внедрить состояние дочерним элементам вашего объекта через React.cloneElement, уходящий компонент не является одним из этих дочерних элементов.
У меня есть небольшое приложение, которое содержит навигационное меню и маршруты, вложенные между контейнером коммутатора. При каждом щелчке по элементу навигации я проверяю, выше или ниже индекс, чтобы соответственно установить состояние анимации (влево или вправо), а затем сохраняю новый индекс элемента навигации, по которому щелкнули.
Каждый раз, когда я переключаю маршруты, применяемая анимация имеет либо fade-left, либо fade-right. Теперь все это работает нормально, но единственная проблема в том, что когда класс переключается вправо и влево, примененная анимация EXIT использует предыдущий данный класс.
Я понимаю, почему это происходит, потому что используется класс выхода, который изначально установлен, и когда новый класс применяется только при втором изменении, новый выход вступает в силу. Документация по переходу очень ограничена, и я ничего не смог найти.
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, применяемые к переходам:
.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;
}
1 ответ
Причиной вашей проблемы является то, что выходящий компонент уже отсоединен и поэтому не получает никаких обновлений. Вы можете найти очень хорошее объяснение вашей проблемы здесь.
Вы можете использовать опору childFactory из <TransitionGroup>
чтобы решить это:
childFactory
Возможно, вам придется применить реактивные обновления к ребенку, когда он выходит. Обычно это делается с помощью cloneElement, однако в случае выходящего дочернего элемента элемент уже удален и недоступен для потребителя.
Если вам нужно обновить ребенка по мере его выхода, вы можете предоставить childFactory, чтобы обернуть каждого ребенка, даже тех, которые уходят.
Попробуйте следующие изменения кода в вашем методе рендеринга:
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>
);
}