question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Maximum update depth exceeded

See original GitHub issue

Just refactoring the basic example to extract scene 2 into a separate component leads to a recursive update and a react error Maximum update depth exceeded. The line which is causing this error is

        ref={props.onSetScene2Ref}

Which in turn calls

 this.setState({ scene2Ancestor: nodeFromRef(ref) })

The ref seems to be alternating between null and a defined ref value but not sure why. Any suggestions what to try?

import * as React from 'react'
import { View, StyleSheet, Animated, Dimensions, TouchableOpacity, Image } from 'react-native'
import { SharedElement, SharedElementTransition, nodeFromRef } from 'react-native-shared-element'

export class Example extends React.Component {
  state = {
    progress: new Animated.Value(0),
    isScene2Visible: false,
    isInProgress: false,
    scene1Ancestor: null,
    scene1Node: null,
    scene2Ancestor: null,
    scene2Node: null,
  }

  onPressNavigate = () => {
    this.setState({ isScene2Visible: true, isInProgress: true })
    Animated.timing(this.state.progress, {
      toValue: 1,
      duration: 1000,
      useNativeDriver: true,
    }).start(() => this.setState({ isInProgress: false }))
  }

  onPressBack = () => {
    this.setState({ isInProgress: true })
    Animated.timing(this.state.progress, {
      toValue: 0,
      duration: 1000,
      useNativeDriver: true,
    }).start(() => this.setState({ isScene2Visible: false, isInProgress: false }))
  }

  onSetScene1Ref = (ref: View | null) => {
    this.setState({ scene1Ancestor: nodeFromRef(ref) })
  }

  onSetScene2Ref = (ref: View | null) => {
    this.setState({ scene2Ancestor: nodeFromRef(ref) })
  }

  render() {
    const { state } = this
    const { width } = Dimensions.get('window')
    return (
      <>
        <TouchableOpacity
          style={{ flex: 1, backgroundColor: '#ecf0f1' }}
          activeOpacity={0.5}
          onPress={state.isScene2Visible ? this.onPressBack : this.onPressNavigate}
        >
          {/* Scene 1 */}
          <Animated.View
            style={{
              ...StyleSheet.absoluteFillObject,
            }}
          >
            <View
              style={{
                ...StyleSheet.absoluteFillObject,
                backgroundColor: 'white',
                justifyContent: 'center',
                alignItems: 'center',
              }}
              ref={this.onSetScene1Ref}
            >
              <SharedElement onNode={node => this.setState({ scene1Node: node })}>
                <Image style={styles.image1} source={require('./logo.png')} />
              </SharedElement>
            </View>
          </Animated.View>

          {/* Scene 2 */}
          {state.isScene2Visible ? (
            <Scene2
              progress={state.progress}
              onSetScene2Ref={this.onSetScene2Ref.bind(this)}
              setState={this.setState.bind(this)}
            />
          ) : undefined}
        </TouchableOpacity>

        {/* Transition overlay */}
        {state.isInProgress ? (
          <View style={styles.sharedElementOverlay} pointerEvents="none">
            <SharedElementTransition
              start={{
                node: state.scene1Node,
                ancestor: state.scene1Ancestor,
              }}
              end={{
                node: state.scene2Node,
                ancestor: state.scene2Ancestor,
              }}
              debug
              position={state.progress}
              animation="move"
              resize="auto"
              align="auto"
            />
          </View>
        ) : undefined}
      </>
    )
  }
}

function Scene2(props: any) {
  return (
    <Animated.View
      style={{
        ...StyleSheet.absoluteFillObject,
        opacity: props.progress,
      }}
    >
      <View
        style={{
          ...StyleSheet.absoluteFillObject,
          backgroundColor: '#00d8ff',
          justifyContent: 'center',
          alignItems: 'center',
        }}
        ref={props.onSetScene2Ref}
      >
        <SharedElement onNode={node => props.setState({ scene2Node: node })}>
          <Image style={styles.image2} source={require('./logo.png')} />
        </SharedElement>
      </View>
    </Animated.View>
  )
}

const styles = StyleSheet.create({
  image1: {
    resizeMode: 'cover',
    width: 160,
    height: 160,
    // Images & border-radius have quirks in Expo SDK 35/36
    // Uncomment the next line when SDK 37 has been released
    //borderRadius: 80
  },
  image2: {
    resizeMode: 'cover',
    width: 300,
    height: 300,
    borderRadius: 0,
  },
  sharedElementOverlay: {
    ...StyleSheet.absoluteFillObject,
  },
})

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:3
  • Comments:6

github_iconTop GitHub Comments

1reaction
mfbx9da4commented, Jul 15, 2022

Ah gotcha! Yeah so the actual issue is caused by onSetScene2Ref={this.onSetScene2Ref.bind(this)} because this.onSetScene2Ref was already bound to this correctly via onSetScene2Ref = (ref: View | null) => { ... definition and the .bind(... was attempting to rebind this which broke things.

1reaction
p-sychecommented, Jul 15, 2022

@mfbx9da4 well, that’s interesting 🤓

It seems the error was in a different spot 😅 Try changing line 112:

onSetScene2Ref={this.onSetScene2Ref}

to

onSetScene2Ref={this.onSetScene2Ref.bind(this)}

This looks like it’s making the issue come back. Which confirms that this is a React usage issue and not react-native-shared-element issue. However it’s a slightly different issue from what I thought first 🤷 😅

Read more comments on GitHub >

github_iconTop Results From Across the Web

ReactJS: Maximum update depth exceeded error
Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate.
Read more >
Fix the "Maximum Update Depth Exceeded" Error in React
Fix the "Maximum Update Depth Exceeded" Error in React ... React is an excellent framework, but it can have some tricky “gotchas.” One...
Read more >
Maximum update depth exceeded warning in React
Maximum update depth exceeded warning in React ... This warning can often happen when a component sets the state inside the useEffect hook....
Read more >
Maximum update depth exceeded problem without using ...
"Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have ...
Read more >
Maximum update depth exceeded. This can happen when a ...
Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found