brentvatne / react-native-overlay

An <Overlay /> component that brings content inside to the front of the view regardless of its current position in the component tree.
639 stars 79 forks source link

Move objects to overlay without re-rendering #14

Closed LeoFidjeland closed 8 years ago

LeoFidjeland commented 9 years ago

Hiya!

I'm trying to animate a MapView so that when it's pressed, it goes from being an element in a ScrollView to the map covering the entire screen (including navigation and status bars).

I've got it sort of working by:

  1. measuring the map position with UIManager.measure
  2. activating the overlay and rendering the same map but now inside an overlay
  3. positioning the map relative to the overlay based on measurement
  4. animating the map size to cover the entire screen

The problem is that when going to/from overlay, the entire map reloads which effectively kills the magic of the animation.

From what I understand, since I move the MapView pretty far in the VDOM tree, React kills it and inits a new one. I've tried to avoid this by initialising the element in a wrapper component and then passing it as a prop. So that the prop itself will not be changed, just where it is placed in the tree. Unfortunately this doesn't help.. It is still being re-instantiated.

I also tried wrapping the MapView in another component and having shouldComponentUpdate always returning false. Doesn't help either..

What's going on here? Is there someway I can retain a reference to the MapView component and tell React that it shouldn't re-initialize it just because it got moved in the tree?

PS. I'm totally in love with react-naive!! Ds.

brentvatne commented 9 years ago

Heya @LeoFidjeland - have you tried setting the key on the MapView to be the same when inside of the overlay? That could quite possibly fix it :smile: If not, let me know and we can look further

LeoFidjeland commented 9 years ago

Great idea! Got the same suggestion in this StackOverflow question I asked.

Does not work unfortunately.. I've stripped away everything until the map isn't destroyed, and it turns with the code below, adding a wrapper view around the map seems to be what is triggering the destroy. Or I'm using key in a weird way:

WORKING:

render() {
    var map = (
        <MapView
          key="theMapView"
          style={styles.map}
        />);
    if(this.state.isOverlay){
      return this.renderOverlay(map);
    }else{
      return this.renderNormal(map);
    }
}

renderNormal(map){
    return (
      <View style={styles.mapWrapper}>
            {map}
        <TouchableWithoutFeedback onPress={(event) => this.mapPressed(event)}>
          <View style={styles.mapButton} />
        </TouchableWithoutFeedback>
      </View>
    );
 }

renderOverlay(map){
    return(
      <View>
          {map}
      </View>
    );
  }

When I add a simple wrapper View to the MapView, it destroys and recreates:

NOT WORKING:

renderNormal(map){
  return (
    <View style={styles.mapWrapper}>
      <View>
          {map}
      </View>
      <TouchableWithoutFeedback onPress={(event) => this.mapPressed(event)}>
        <View style={styles.mapButton} />
      </TouchableWithoutFeedback>
    </View>
  );
}

What's going on here?

edit: Everything concerning Overylay is removed in this example, so it's definitely not an issue with this library, but of React, or (most likely) how I'm (mis)using React. :)

niftylettuce commented 8 years ago

going to close, if you can document how you fixed or if its still an issue -- maybe go file an issue in React Native for help there?

niftylettuce commented 8 years ago

See #36 - we will be refactoring this soon to support Android/iOS and not have any issues here, there will no longer be the XCode integration needed

LeoFidjeland commented 8 years ago

Still an issue, not solved.

Opened a React Native issue here https://github.com/facebook/react-native/issues/2387

That answered some questions but I never really got it to work.

The issue is that moving something to/from an overlay moves it in the react tree more than one level, which causes react to destroy and re-init the component. As a workaround I tried initiating multiple components and showing/hiding them, but that leads to other problems. If they are totally hidden react optimizes them away and does not render them, if they are slightly shown they start blocking the touch events.

If anyone has any Idea on how to solve it, please comment here or on the RN issue!

Closing this issue.