React TransitionGroup e React.cloneElement não enviam adereços atualizados

Estou seguindo o tutorial de Chang Wang para fazer transições React reutilizáveis com HOCs eReactTransitionGroup(Parte 1 Parte 2) em conjunto com o tutorial de Huan Ji sobre transições de página (Ligação)

O problema que estou enfrentando é queReact.cloneElementparece não estar passando adereços atualizados em um de seus filhos, enquanto outros filhos recebem propriamente adereços atualizados.

Primeiro, algum código:

TransitionContainer.js

TransitionContainer é um componente de contêiner que é semelhante aApp no tutorial de Huan Ji. Ele injeta uma fatia do estado nas crianças.

Os filhos daTransitionGroup são todos uma instância de um HOC chamadoTransition (código mais abaixo)

import React from 'react';
import TransitionGroup from 'react-addons-transition-group';
import {connect} from 'react-redux';
class TransitionContainer extends React.Component{
  render(){
    console.log(this.props.transitionState);
    console.log("transitionContainer");
    return(
      <div>
      <TransitionGroup>
      {
        React.Children.map(this.props.children,
         (child) => React.cloneElement(child,      //These children are all instances of the Transition HOC
           { key: child.props.route.path + "//" + child.type.displayName,
             dispatch: this.props.dispatch,
             transitionState: this.props.transitionState
           }
         )
        )
      }

      </TransitionGroup>
      </div>
    )
  }
}
export default connect((state)=>({transitionState:state.transitions}),(dispatch)=>({dispatch:dispatch}))(TransitionContainer)

Transition.js

Transition é semelhante ao HOC de Chang Wang. São necessárias algumas opções, define ocomponentWillEnter + componentWillLeave ganchos e envolve um componente.TransitionContainer (acima) injetaprops.transitionState nesse HOC. No entanto, às vezes, os objetos não são atualizados mesmo que o estado seja alterado (consulteO problema abaixo)

import React from 'react';
import getDisplayName from 'react-display-name';
import merge from 'lodash/merge'
import classnames from 'classnames'
import * as actions from './actions/transitions'
export function transition(WrappedComponent, options) {
  return class Transition extends React.Component {
    static displayName = `Transition(${getDisplayName(WrappedComponent)})`;
    constructor(props) {
      super(props);
      this.state = {
          willLeave:false,
          willEnter:false,
          key: options.key
      };
    }
    componentWillMount(){
      this.props.dispatch(actions.registerComponent(this.state.key))
    }
    componentWillUnmount(){
      this.props.dispatch(actions.destroyComponent(this.state.key))
    }
    resetState(){
      this.setState(merge(this.state,{
        willLeave: false,
        willEnter: false
      }));
    }
    doTransition(callback,optionSlice,willLeave,willEnter){
      let {transitionState,dispatch} = this.props;
      if(optionSlice.transitionBegin){
        optionSlice.transitionBegin(transitionState,dispatch)
      }
      if(willLeave){
        dispatch(actions.willLeave(this.state.key))
      }
      else if(willEnter){
        dispatch(actions.willEnter(this.state.key))
      }
      this.setState(merge(this.state,{
        willLeave: willLeave,
        willEnter: willEnter
      }));
      setTimeout(()=>{
        if(optionSlice.transitionComplete){
          optionSlice.transitionEnd(transitionState,dispatch);
        }
        dispatch(actions.transitionComplete(this.state.key))
        this.resetState();
        callback();
      },optionSlice.duration);
    }
    componentWillLeave(callback){
      this.doTransition(callback,options.willLeave,true,false)
    }
    componentWillEnter(callback){
      this.doTransition(callback,options.willEnter,false,true)
    }
    render() {

      console.log(this.props.transitionState);
      console.log(this.state.key);

      var willEnterClasses = options.willEnter.classNames
      var willLeaveClasses = options.willLeave.classNames
      var classes = classnames(
        {[willEnterClasses] : this.state.willEnter},
        {[willLeaveClasses] : this.state.willLeave},
      )
      return <WrappedComponent animationClasses={classes} {...this.props}/>
    }
  }
}

opções

As opções têm a seguinte estrutura:

{
  willEnter:{
    classNames : "a b c",
    duration: 1000,
    transitionBegin: (state,dispatch) => {//some custom logic.},
    transitionEnd: (state,dispatch) => {//some custom logic.}
         // I currently am not passing anything here, but I hope to make this a library
         // and am adding the feature to cover any use case that may require it.

  },
  willLeave:{
    classNames : "a b c",
    duration: 1000,
    transitionBegin: (state,dispatch) => {//some custom logic.},
    transitionEnd: (state,dispatch) => {//some custom logic.}

  }
}

Ciclo de vida da transição (onEnter ou onLeave)

Quando o componente está montado,actions.registerComponent é despachadocomponentWillMountQuando o componentecomponentWillLeave oucomponentWillEnter gancho é chamado, a fatia correspondente das opções é enviada paradoTransitionEm doTransition:A função transitBegin fornecida pelo usuário é chamada (optionSlice.transitionBegin)O padrãoaction.willLeave ouaction.willEnter é despachadoUm tempo limite é definido para a duração da animação (optionSlice.duration) Quando o tempo limite estiver concluído:A função transitEnd fornecida pelo usuário é chamada (optionSlice.transitionEnd)O padrãoactions.transitionComplete é despachado

Essencialmente, o optionSlice apenas permite ao usuário passar algumas opções.optionSlice.transitionBegin eoptionSlice.transitionEnd são apenas funções opcionais que são executadas durante a animação, se isso for adequado para um caso de uso. No momento, não estou passando nada para meus componentes, mas espero tornar isso uma biblioteca em breve, então estou apenas cobrindo minhas bases.

Por que estou rastreando os estados de transição?

Dependendo do elemento que está entrando, a animação existente muda e vice-versa.

Por exemplo, na imagem acima, quando o azul entra, o vermelho se move para a direita e, quando o azul sai, o vermelho se move para a esquerda. No entanto, quando o verde entra, o vermelho se move para a esquerda e, quando o verde sai, o vermelho se move para a direita. Para controlar isso, é preciso saber o estado das transições atuais.

O problema:

oTransitionGroup contém dois elementos, um entrando e um saindo (controlado pelo reat-router). Ele passa por um suporte chamadotransitionState para seus filhos. oTransition HOC (filhos deTransitionGroup) despacha certas ações de redux ao longo de uma animação. oTransition O componente que está entrando recebe as alterações de adereços conforme o esperado, mas o componente que está saindo está congelado. É adereços não mudam.

É sempre aquele que está saindo que não recebe adereços atualizados. Tentei alternar os componentes empacotados (saindo e entrando) e os problemas não se devem aos componentes empacotados.

Imagens

Transição na tela:

Transição no DOM de reação

O componente existente Transition (Connect (Home))), neste caso, não está recebendo acessórios atualizados.

Alguma idéia de por que esse é o caso? Agradecemos antecipadamente por toda a ajuda.

Atualização 1:

import React from 'react';
import TransitionGroup from 'react-addons-transition-group';
import {connect} from 'react-redux';
var childFactoryMaker = (transitionState,dispatch) => (child) => {
  console.log(child)
  return React.cloneElement(child, {
    key: (child.props.route.path + "//" + child.type.displayName),
    transitionState: transitionState,
    dispatch: dispatch
  })
}

class TransitionContainer extends React.Component{
  render(){
    let{
      transitionState,
      dispatch,
      children
    } = this.props
    return(
      <div>
      <TransitionGroup childFactory={childFactoryMaker(transitionState,dispatch)}>
          {
            children
          }
      </TransitionGroup>
      </div>
    )
  }
}

export default connect((state)=>({transitionState:state.transitions}),(dispatch)=>({dispatch:dispatch}))(TransitionContainer)

Eu atualizei meuTransitionContainer para o acima. Agora ocomponentWillEnter ecomponentWillLeave ganchos não estão sendo chamados. Eu registrei oReact.cloneElement(child, {...}) nochildFactory e os ganchos (assim como minhas funções definidas, comodoTransition) estão presentes noprototype atributo. Somenteconstructor, componentWillMount ecomponentWillUnmount são chamados. Eu suspeito que isso é porque okey suporte não está sendo injetado atravésReact.cloneElement. transitionState edispatch estão sendo injetados.

Atualização 2:

import React from 'react';
import TransitionGroup from 'react-addons-transition-group';
import {connect} from 'react-redux';
var childFactoryMaker = (transitionState,dispatch) => (child) => {
  console.log(React.cloneElement(child, {
    transitionState: transitionState,
    dispatch: dispatch
  }));
  return React.cloneElement(child, {
    key: (child.props.route.path + "//" + child.type.displayName),
    transitionState: transitionState,
    dispatch: dispatch
  })
}

class TransitionContainer extends React.Component{
  render(){
    let{
      transitionState,
      dispatch,
      children
    } = this.props
    return(
      <div>
      <TransitionGroup childFactory={childFactoryMaker(transitionState,dispatch)}>
      {
        React.Children.map(this.props.children,
            (child) => React.cloneElement(child,      //These children are all instances of the Transition HOC
                { key: child.props.route.path + "//" + child.type.displayName}
            )
        )
      }
      </TransitionGroup>
      </div>
    )
  }
}

export default connect((state)=>({transitionState:state.transitions}),(dispatch)=>({dispatch:dispatch}))(TransitionContainer)

Após uma inspeção mais aprofundada da fonte do TransitionGroup, percebi que coloquei a chave no lugar errado. Tudo está bem agora. Muito obrigado pela ajuda !!

questionAnswers(1)

yourAnswerToTheQuestion