Сложная анимация возможна с 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>
    )
  }
});
Другие вопросы по тегам