ReactTransitionGroup doesn't works with React-

2019-07-09 00:14发布

问题:

I'm working on a bigger project but I created this short example to illustrate the problem.

If I use Box component, its works. It outputs in the console componentWillEnter and componentWillLeave when we click on the button.

If I use BoxContainer container, it doesn't work anymore. componentWillEnter and componentWillLeave special lifecycle hooks are not called.

{this.state.shouldShowBox && <BoxContainer/>}

Webpack build is done correctly, no errors in the console, but It outputs nothing.

I also tried with high-level API :ReactCSSTransitionGroup, and it works with Box and BoxContainer component. But I need to use the low-level API : ReactTransitionGroup.

Do you have an idea why it doesn't works when we use react-redux?

Version used :

  • react : 15.0.2
  • redux : 3.5.2
  • react-redux : 4.4.5

Code :

import React from 'react';
import {render} from 'react-dom';
import {Provider, connect} from 'react-redux';
import {createStore, compose, combineReducers} from 'redux';
import TransitionGroup from 'react/lib/ReactTransitionGroup';

// Box component
class Box extends React.Component {
  componentWillEnter(callback) {
    console.log('componentWillEnter');
    callback();
  }

  componentWillLeave(callback) {
    console.log('componentWillLeave');
    callback();
  }

  render() {
    return <div className="box"/>;
  }
}

// Boxe connected component
const BoxContainer = connect(null, {})(Box);

// App component
class App extends React.Component {
  state = {
    shouldShowBox: true
  };

  toggleBox = () => {
    this.setState({
      shouldShowBox: !this.state.shouldShowBox
    });
  };

  render() {
    return (
      <div>
        <TransitionGroup>
          {this.state.shouldShowBox && <BoxContainer/>}
        </TransitionGroup>
        <button className="toggle-btn" onClick={this.toggleBox}>
          toggle
        </button>
      </div>
    );
  }
}

// reducer
function reducer(state = [], action) {
  switch (action.type) {
    default:
      return state
  }
}

// store
const store = createStore(reducer);

// render
render(
  <Provider store={store}>
    <App />
  </Provider>
  ,
  document.getElementById('root')
);

回答1:

That is not supposed to work because connect wraps your component into a "connected" object, however, there are some workarounds like connect-with-transition-group

The creator of Redux, Dan Abramov, has said this about the issue

To be completely honest I don’t want to hardcode supports for transition groups into connect(). This is a very specific API that is not going to be the React animation API and acts more like an escape hatch until there are better solutions. The way it invokes instance methods on a nested instance does not align with React conceptual model very well.

I would suggest you to:

  • Either write your own wrapper around connect() like you suggested

  • Or use a more React-friendly approach to animations such as https://github.com/chenglou/react-motion

Either write your own wrapper around connect() like you suggested Or use a more React-friendly approach to animations such as https://github.com/chenglou/react-motion



回答2:

We also tried to do the same thing, hooking up TransitionGroup with redux connected component, like

<TransitionGroup>
  layerIds.map(id => ( <Layer ...>))
</TransitionGroup>

where Layer itself is a connected redux component.

We also tried wrap Layer ourselves like

const WrappedLayer = (props) =>{
  return <TransitionGroup>
  <Layer {...props}/>
  </TransitionGroup>
}

And connect it using WrappedLayer, it will only work on mounting stage like componentWillAppear and componentDidAppear, will not work on unmounting stage, since when you delete a layer on UI, the TransitionGroup is also deleted, then life cycle method like componentWillLeave will never be triggered.

Good news is that we finally find a very handy library react-move https://github.com/react-tools/react-move , which we think is better than react-motion, since we can custom the duration, the animation curve, and it is very clean.

Hopefully, this will help you, if you meet any problem by using react-move, just msg me.