Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Native: Animation when component unmounts

I have a custom modal which slides in upon componentDidMount:

componentDidMount() {

    Animated.timing(this._animatedValue.y, {
        duration: 200,
        toValue: 0
    }).start()

} 

Ok, this was easy. However, I also like to slide the modal out when the component unmounts. For me, componentWillUnmount() would feel right, as it is an elegant declarative way:

componentWillUnmount() {

    Animated.timing(this._animatedValue.y, {
        duration: 200,
        toValue: deviceHeight
    }).start()

} 

But this does of course not work, because the React doesnt wait until I have finished my animation.

So currently I work around this with a custom function:

closeModal() {


    Animated.timing(this._animatedValue.y, {
        duration: C.filterModalDuration,
        toValue: deviceHeight
    }).start()

   InteractionManager.runAfterInteractions(() => {
     this.props.UnmountThisComponent()
   })

}

This is of course not as elegant, but it works. However, the pain begins if I need to call this function from a component far down in the component tree, i.e. I need to manually pass down this function via onUnmount={()=> closeModal()} and then with onUnmount={this.props.onUnmount} over and over again...

Then I thought that I could solve this with redux & redux-connect. I was thinking to trigger a redux state change from the child components, which would then call the function via componentWillRecieveProps() like this:

componentWillReceiveProps (nextProps) {

  if (nextProps.closeFilter === true) {
          this.closeModal()
  }

}

However this feels pretty hacky and imperative.

Is there any way to solve this problem in an elegant / declarative way?

like image 893
ThorbenA Avatar asked May 06 '16 17:05

ThorbenA


People also ask

What is mounting and unmounting in React?

A React component's lifecycle contains distinct phases for creation and deletion. In coding terms, these are called mounting and unmounting. You can also think of them as "setup" and "cleanup".

What is mounting in React JS?

Mounting means putting elements into the DOM. React has four built-in methods that gets called, in this order, when mounting a component: constructor() getDerivedStateFromProps() render()


2 Answers

I would not use InteractionManager.runAfterInteractions to execute after an animation completes. I recommend using the start callback.

Animated.timing(this.animatedValue, {}).start(() => this.props.closeModal())

There are things like https://github.com/mosesoak/react-native-conductor which can help you coordinate deep animations and fire back up. This takes advantage of context.

You could also use redux as you have tried however I would use componentDidUpdate rather than componentWillReceiveProps.

The reason is that it is only safe to cause a setState in the component you have your componentWillReceiveProps in.

If you trigger a dispatch inside of componentWillReceiveProps it will cause a setState in other components cause your application to break.

Overall: I would recommend this flow. (Close Action Initiated) => Animate Modal Closed => in start(() => {}) callback cause a setState or set a piece of data in your redux store that will then unmount your modal which is now hidden.

This way you get the unmount animation.

If you are using routing like react-navigation I recommend setting up a mode: "modal" navigation style. That way the unmounting/mounting modal animations are taken care of for you.

like image 81
browniefed Avatar answered Nov 23 '22 10:11

browniefed


componentWillReceiveProps seems to fit perfectly as it's intent is to make actions based on next props. This is ideal when parents want to trigger actions on their childrens (even through this is not really the pattern of React where children call parents functions, and parents receive events from childrens).

like image 38
Despirithium Avatar answered Nov 23 '22 10:11

Despirithium