user1971466
user1971466

Reputation:

ReactNative componentDidMount doesn't get called

I have two screens: A and B, connected with a StackNavigator

Screen A is a QR code scanner. As soon as a QR code is scanned, it navigates to screen B.

In screen B, I make an API call using the QR code that gets passed as a navigation param from screen A. I trigger this API call in componentDidMount.

My issue is: if I navigate from A to B, then back to A, then to B again, componentDidMount does not get called and I have no way to trigger the API call.


EDIT:

Here's some code

Screen A

Handler function that gets called when a QR code is scanned:

handleQRCode = qrCode => {
    NavigationService.navigate('Decode', {qrCode});
};

Screen B

The QR code is pulled from the navigation state params and used for an API call (startDecode) through redux.

componentDidMount() {
    qrCode = this.props.navigation.state.params.qrCode;
    this.props.startDecode(qrCode.data);
}

My issue is that componentDidMount only gets called the first time that route is taken.

Upvotes: 1

Views: 5619

Answers (3)

Uzair A.
Uzair A.

Reputation: 1638

I was facing a similar issue and I used this.props.navigation.addListener() to resolve it. Basically, force-calling componentDidMount() may be possible by pushing same screen again using a key (I haven't tried it) but your stack will keep growing as well, which is not optimal. So, when you return to a screen already in stack, you can use addListener() to see if it is being re-focused, and you can replicate you componentDidMount() code here:

class MyClass extends Component {

  someProcess = () => {
    // Code common between componentDidMount() and willFocus()
  }

  componentDidMount() {
    this.someProcess();
  }

  willFocus = this.props.navigation.addListener(
    'willFocus',
    (payload) => {
      this.someProcess();
    }
  );

}

When MyClass is called for the first time, componentDidMount will get called. For the other times when it is still in stack but instead just gains focus, addListener will get called.

Upvotes: 2

Asaf David
Asaf David

Reputation: 3297

In react-navigation each screen is kept mounted. This means that when you you go back to B, you might have changed the props, but componentDidMount was already invoked in the first creation of this screen.

There are two options available for you (AFAIK) that can handle this case:

  1. Instead of calling this.props.navigation.navigate() you can use this.props.navigation.push which will create another instance of screen B, thus invoking the componentDidMount React lifecycle event.
  2. In screen B you can catch the event where its props have changed. This can take place in the new static lifecycle event getDerivedPropsFromState or it can be done in the soon to be deprecated componentWillReceiveProps.

Upvotes: 2

Andre Knob
Andre Knob

Reputation: 831

This happens because the B component is mounted only on the first time it is accessed, so componentDidMount won't be called again.

I recommend you to pass a callback to the setOnNavigatorEvent method of your navigator, with the 'didAppear' event. Your callback will be invoked on every event emitted by react-native-navigation, and you can verify to do your logic every time the screen appears (hence the use of 'didAppear' event). You can base your code on the following:

export default class ExampleScreen extends Component {
  constructor(props) {
    super(props);
    this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this));
  }

  onNavigatorEvent(event) {
    if (event.id === 'didAppear') {
      // do API call here
    }
  }
}

Upvotes: 0

Related Questions