React-native-router-flux: [Bug] ComponentWillMount/DidMount/WillUnmount fires after Actions.pop()

Created on 22 Oct 2017  路  29Comments  路  Source: aksonov/react-native-router-flux

Hello!

After migrating from v3 to v4 I see this problem:

When push 3 scenes to stack and then go back with Actions.pop() 3 times lifecycle methods will be called on same components again after unmount.

My guess that is component will get remounted and then immedeately unmounted.

index.ios.bundle?platform=ios&dev=true&minify=false:164287 componentDidMount
index.ios.bundle?platform=ios&dev=true&minify=false:164298 componentDidUpdate
index.ios.bundle?platform=ios&dev=true&minify=false:164298 componentDidUpdate
index.ios.bundle?platform=ios&dev=true&minify=false:164298 componentDidUpdate
index.ios.bundle?platform=ios&dev=true&minify=false:164308 componentWillUnmount
index.ios.bundle?platform=ios&dev=true&minify=false:164279 componentWillMount
index.ios.bundle?platform=ios&dev=true&minify=false:164287 componentDidMount
index.ios.bundle?platform=ios&dev=true&minify=false:164308 componentWillUnmount

Version

Tell us which versions you are using:

  • react-native-router-flux v4.0.0-beta22
  • react-native v0.50-rc

Expected behaviour

Components lifecycle methods called again ComponentWillMount/DidMount/WillUnmount

Actual behaviour

Should not call lifecycle methods after unmount.

Steps to reproduce

For non-obvious bugs, please fork this component, modify Example project to reproduce your issue and include link here.

  1. Go to 3 scenes deep
  2. Call programmatically
for ( let x in new Array(3).fill() ) {
  await Actions.pop();
}
  1. See problem in console

Most helpful comment

Hello @fadlykayo ! I've migrated to react-navigation today

All 29 comments

Are these nested same Scenes? Cause react 16 talks about something that might be related to this (out of order calls).

Component Lifecycle

Since React prioritizes the rendering, you are no longer guaranteed componentWillUpdate and shouldComponentUpdate of different components will fire in a predictable order. The React team is working to provide an upgrade path for apps that would break from this behavior.
Source: https://edgecoders.com/react-16-features-and-fiber-explanation-e779544bb1b7

@daviscabral Hello!

When I do Actions.pop components that should just unmount will unmount and remount and unmount again. I don't think it's React related

I see. Are you using redux? I am asking to see if Is there any way to track the page actions.

@kesha-antonov Looks like your Router is not top-level and you are recalling it, probably with different params. I tried to reproduce your issue with Example provided by this component without success (from Login3 page). Please fork and modify Example as requested initially.

@daviscabral I use mobx.

@aksonov Thank you for looking at it. I'll provide an example.

I have

<View>
  <Router ...>
    {this.scenes()}
  </Router>
   ...other Components
</View>

Ok. Solved it with other way
Closing for now

It's definitely something wrong @aksonov
Because when I call Actions.tabbar({ type: ActionConst.RESET })
(see https://github.com/aksonov/react-native-router-flux/issues/2595)

it remounts signIn scene twice. I think this is also cause of this error: Could not locate shadow view with tag #122, this is probably caused by a temporary inconsistency between native views and shadow views.

screen shot 2017-11-05 at 18 28 24

Now try to do the same with pure react-navigation and check results. RNRF doesn't do almost any rendering.

Ok. Maybe it's my app related.

I found out that my App and Router re-renders after sign in.

screen shot 2017-11-05 at 19 16 27

What's be best way to solve it?
If you need to re-render component with Router. But not Router itself @aksonov

Ok. Rewrote without re-render
Same errors

When I disabled Actions.refresh on scene where I go from signIn errors disappear. SignIn will unmount and no errors/warnings.

Something wrong with Actions.refresh

Wrapping Actions.refresh in `InteractionManager.runAfterInteractions helped. No errors/warnings

So I think they appear if Actions.refresh called on new scene when previous is not unmounted yet. What do you think? @aksonov

Ref: https://github.com/react-community/react-navigation/issues/2702

--- UPDATE ---

Yes. Errors/warnings disappear when previous scenes is unmounted completely (componentWillUnmount called).

If prev scene is not unmounted (componentWillUnmount not called yet) and we call Actions.refresh on the next scene - then prev scene get's remounted twice and errors/warnings appear.

This happens with Actions.pop and Actions.tabbar({ type: 'reset' })

It looks very useful, could you submit PR?

Wrapping Actions.refresh in InteractionManager.runAfterInteractions helped. No errors/warnings

This is bad idea. If you're talking about this.

We should detect that prev scene is unmounted componentWillUnmount called and if not skip setProps in Actions.refresh

Have you tried just to wrap it with setTimeout ?

No. Now I track it in mobx store

Good suggestion

@aksonov
Yes. setTimeout works

But if I use

refresh = (data) => {
    const key = getActiveState(this._state).key;
    const params = filterParam(data);
    setTimeout(() => {
      this.dispatch(NavigationActions.setParams({ key, params }));
    })
  };

for all scenes I see delay of rendering title, navbar buttons.

So this is what is going on:

Actions.tabbar({ type: 'reset', ... })

  1. Blur current scene_1
  2. Focus next scene_2
  3. componentDidMount in scene_2
  4. Call Actions.refresh
  5. Since scene_1 is not unmounted yet setParams is called on that scene
  6. componentWillUnmount, componentDidMount, componentWillUnmount called on scene_1

@kesha-antonov It is interesting. We could easily modify our Reducer and process SET_PARAMS by RNRF (not to forward to RN). Could you try @gaodeng receipt?

Tried but didn't understand RNRF code.
Can you please help try adapt that code? @aksonov

Sorry, don't have time. You may check Reducer.js and its code. For many actions it just forwards requests to navigationStore.router.getStateForAction. You may add own if else block for REFRESH action (and remove it from supportedActions map)

Ok. Thanks! I'll find solution.

Closed because it is not related to RNRF.

i have the same problem,use Actions.pop({refresh: {update: new Date()}})銆倃hat i should do

@kesha-antonov hi, do you found any solution for this? my current workaround is by adding setTimeout(() => { Actions.productListing({type: 'replace'}), 0);. But it still give me flicker effect. Another workaround is by adding a custom loader before the next scene mounted. But the loader will always be rendered everytime the next scene is called.

UPDATE:
Found the best solution so far by rendering an empty View, before navigating to the next scene.

shouldComponentUpdate(nextProps, nextState) {
    if (nextProps.status === 'ACTIVE') {
      Actions.productListing({ type: 'replace' });
    };

    return true;
  };

render() {
    if (this.props.status === 'ACTIVE') {
      return <View></View>;
    } else {
      return this.renderSubmitRegistration();
    }
  };

Hello @fadlykayo ! I've migrated to react-navigation today

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jgibbons picture jgibbons  路  3Comments

rafaelcorreiapoli picture rafaelcorreiapoli  路  3Comments

GCour picture GCour  路  3Comments

sarovin picture sarovin  路  3Comments

moaxaca picture moaxaca  路  3Comments