Сложная анимация возможна с ReactCSSTransitionGroup и React Router?
Мне интересно, подходит ли ReactCSSTransitionGroup для моего варианта использования или нет.
На одном из маршрутов у меня есть кнопка поиска, когда пользователь нажимает на нее, кнопка должна уходить, пока она загружается на странице поиска. После загрузки некоторая область страницы будет анимирована со стороны.
Я использую это с React Router, чтобы переходы по всей странице казались простыми, но анимация определенных элементов таким способом кажется более сложной.
Должен ли ReactCSSTransitionGroup справиться с этим или я должен искать альтернативы?
2 ответа
Я думаю, что ответ "Да, это возможно".
Я написал доказательство концепции на CodePen. Есть несколько ошибок с ReactCSSTransitionGroup
один из которых упоминается в этом обсуждении в группах Google. Там кто-то говорит:
Вы должны держать ReactCSSTransitionGroup вокруг и добавлять / удалять ее содержимое.
Так что, в принципе, если у вас есть компонент, который оживит своих потомков, вам нужно обернуть детей в ReactCSSTransitionGroup
, Вот некоторый псевдокод, основанный на моей ручке:
Допустим, настройка вашего маршрутизатора выглядит следующим образом:
<Router history={hashHistory}>
<Route path="/" component={App}>
<IndexRoute component={Home}/>
<Route path="/repos" component={Repos}>
<Route path="/repos/:userName/:repoName" component={Repo}/>
</Route>
<Route path="/about" component={About}/>
</Route>
</Router>
Я хочу оживить дочерние компоненты <App>
, Вот как это может выглядеть:
function App(props) {
return (
<div>
<h1>App</h1>
<nav>
<ul>
<li><NavLink to="/" onlyActiveOnIndex={true}>Home</NavLink></li>
<li><NavLink to="/about">About</NavLink></li>
<li><NavLink to="/repos">Repos</NavLink></li>
</ul>
</nav>
<ReactCSSTransitionGroup>
{React.cloneElement(props.children, {
key: getKey(props.location.pathname)
})}
</ReactCSSTransitionGroup>
</div>
);
}
Обратите внимание, что вам нужно иметь ReactCSSTransitionGroup
вне дочерних компонентов. Кроме того, каждому элементу нужен уникальный ключ, чтобы ReactCSSTransitionGroup
можете отслеживать их. Путь, как правило, хороший кандидат. В моем конкретном случае использования я использовал функцию, чтобы получить определенный префикс пути, чтобы переход на этом уровне не происходил, если я перемещаюсь между репозиториями. Вы поймете, что я имею в виду.
Я могу сделать что-то подобное в <Repos>
составная часть:
function Repos(props) {
return (
<div>
<h2>Repos</h2>
<ul>
<li><NavLink to="/repos/reactjs/react-router">React Router</NavLink></li>
<li><NavLink to="/repos/facebook/react">React</NavLink></li>
</ul>
<ReactCSSTransitionGroup>
{props.children ?
React.cloneElement(props.children, {
key: props.location.pathname
}) :
null}
</ReactCSSTransitionGroup>
</div>
);
}
Подобная идея здесь. На этот раз я использовал полный путь, потому что на этом уровне мне нужен переход между отдельными репозиториями.
Я еще не попробовал это в большом приложении, поэтому я передам слово кому-то с большим опытом. Однако, как я уже говорил ранее, это должно быть по крайней мере возможно. Вы должны иметь возможность создавать простые анимации для получения сложных анимаций.
ReactCSSTransitionGroup
на самом деле интерфейс высокого уровня для ReactTransitionGroup
, Если вы оберните свои дочерние элементы с <TransitionGroup />
, вы получите дополнительные методы жизненного цикла, такие как componentWillEnter(callback)
, componentWillLeave(callback)
и т. д. Вы можете запустить анимацию в этих методах, а затем запустить обратный вызов, когда анимация будет завершена. Я использую jQuery ниже для анимации, но вы можете использовать любую библиотеку анимации для управления элементами.
Код, который иллюстрирует эту концепцию:
<Router history={hashHistory}>
<Route path="/" component={Parent}>
<Route path="/child" component={Child}/>
</Route>
</Router>
var Child = React.createClass({
componentWillEnter: function(callback) {
var $this = $(ReactDOM.findDOMNode(this));
$this.css({ opacity: 0 });
$this.fadeIn('slow', callback);
},
componentWillLeave: function(callback) {
var $this = $(ReactDOM.findDOMNode(this));
$this.fadeOut('slow', callback);
},
render: function() {
return (
<p>This child element will fade in when entering and fade out when leaving.</p>
)
}
});
var Parent = React.createClass({
render: function() {
return (
<h1>Parent element</h1>
<TransitionGroup>
{this.props.children}
</TransitionGroup>
)
}
});