React-native-router-flux: Force re-render scene after pop

Created on 5 Apr 2016  ·  58Comments  ·  Source: aksonov/react-native-router-flux

Hi,

Is it possible to force re-render scene after a click on Back button on a previous state ?

Thx

Most helpful comment

will I finally solve it by calling empty refresh with props after delay
Actions.popTo('pageOne');
setTimeout(() => {
Actions.refresh({name:'zzzzar'});
console.log("zzzz");
}, 10);

All 58 comments

Thanks for your answer but, not work ;)
It doesnt refresh the previous view ...

I guess it should refresh it if something is changed within its state. So set some random value within refresh

On 09 Apr 2016, at 09:51, rtrompier [email protected] wrote:

Thanks for your answer but, not work ;)
It doesnt refresh the previous view ...


You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub https://github.com/aksonov/react-native-router-flux/issues/465#issuecomment-207737400

Could anyone tell me how to refresh after Actions.pop()?

Again, you must change state of previous component to be refreshed. It is how NavigationExperimental API works.

@aksonov I am having the same issue as @helloworld123456 and @rtrompier . My navigation flow looks as follows:

Scene A => Scene B => Scene C

When I pop from C to B, I need to rerender Scene B. I see that @Elyx0 has suggested using Actions.pop(); Actions.refresh(); I have two questions:

  1. Will calling Actions.refresh() rerender Scene C or B?
  2. Is it possible to override the onPress handler of the back button in the navbar? It does not look like it is possible after looking at the code.
  1. It should refresh B, but why don't you test it and find out!
  2. Use renderBackButton to pass in your own back button, custom onPress and all.

Got it - thanks @cridenour

@samdturner can you tell me how?

Thank you

@alfan2305

Actions.pop();
Actions.refresh();

what about within the navBar? Shouldn't we have a refresh=true on the Scene. Otherwise I have to override the onPress for the backButton to a function that calls the above two calls.

@ssomnoremac What's wrong with overriding the button? Pretty simple to do. If this issue was more popular I'd say we add the functionality but it seems to be an edge case.

@cridenour I believe it goes beyond the scope of this question to have the ability to re-render a scene on route change. In my case I want to go back from a registration sequence and have the state of the registration reset in my Redux store by firing an action on re-render instead of hooking the reset into the back button. Is there a better way to accomplish this?

I would think your registration component would receive the change by listening to redux would it not? Or is the issue the scene doesn't re-render after receiving new props when another component rests on top?

I mean we provide an onBack so when defining the registration scene should be as simple as

const refreshOnBack = () => { Actions.pop(); Actions.refresh(); }

...
<Scene key="registration" component={Registration} onBack={refreshOnBack} />
...

thanks, didn't know about onBack as I use the detailedExample as my docs.

No problem. Definitely take a glance through https://github.com/aksonov/react-native-router-flux/blob/master/docs/API_CONFIGURATION.md as there's a lot of flexibility there for when you go "off book" :)

Hello guys,
First of all : thanks you all for your insights they are really useful as I'm quite a newbie in react & javascript coding.

I just tried out the "refreshOnBack" solution from @cridenour : unfortunately I stumbled upon some difficulties.

Now the button just do nothing. I just stay on my "C" Scene (referring to @ssomnoremac example) even if the button highlighted itself. If I just set :
const refreshOnBack = () => { Actions.pop(); }
I've the expected behaviour without an update of my parent view.

What am I missing ? :/

I have the same results as @Brokray

If you debug remotely do you see an error in the console?

@cridenour no errors in the console.
Is there anything I can log to the console to figure out what's going on? Something from the reducer maybe?
The reducer is still a bit of a mystery to me.

Thanks.

Hmm! Maybe try doing the refresh first.

Actions.refresh({key: 'yourSceneKey'}); Actions.pop();

Thanks you for your help @cridenour : I just tried your idea but unfortunately it doesn't work either. I go from C to B without any problems but "B" didn't changed.
It seems that the problem come from the refresh() method : even if I put a refresh button on the 'B' scene (calling to Actions.refresh()) nothing happens.

@jholton I don't know if it can help you but : I found a custom way to update my scene :
I have a reducer for each scene (B & C), when I call my POST action in 'C' both of my reducers catch the call, C does what he need to do and B set a state variable 'update' to true.
This way, in the "ComponentWillReceiveProps" of B, I test 'update', and call again what I need to refresh the scene.

If somebody have more insights on the Actions.refresh() problem, do not hesitate !
Thanks.

@Brokray Interesting that it didn't work - but you have the better solution anyways. I don't believe in trying to use the navigation system to pass app state - I always stick to flux stores.

@Brokray if it's not too much trouble, can you provide an example? How do you have a reducer for a single scene? I've read all the documentation, but it's a bit over my head at this point.

@cridenour Yeah, I don't want to pass app state per se. I just want scene B to re-render.
In scene B, I display some data from by database. In scene C, I have a form that adds data to the database. When the user pops back to scene B, I just want all the lifecycle methods (e.g. getInitialState, componentWillMount, etc) to fire so the newly added data is retrieved and displayed. Those lifecycle methods don't fire.

@jholton Correct, and that is by design from React, for better or worse. I highly suggest you try out a flux implementation (a lot of people like redux, I personally use Alt) and manage the data there. That way, when you update the data, the component will re-render (this means re-running render()) and not be reliant on the initialization of the component. A lot of react problems in React become much easier once you move the data layer away from components (and they just read data and display).

That said, Actions.refresh() will only cause new props and a re-render (again, just render()) but will not call componentWillMount, etc.

@jholton Well, as @cridenour said I use a flux implementation (redux indeed) which allow you to manage your data through actions, state and reducer. Once you're familiar with flux implementation I will gladly provide you an example !
@cridenour Thank you again for your help !

@Brokray Yeah, I'm diving into Redux tutorials now. I'll revisit this thread when I can discuss flux/redux more intelligently. Thanks.

will i succeed in updated props but when i try to move to next view again then its gives me error
this code is written in me setting screen
Actions.pop();
Actions.refresh({key: 'pageOne', name:'wwwww'});

Only this will work and update the view but when i try to again go to the setting screen then it gives me error
screen shot 2016-08-02 at 4 43 38 pm

will I finally solve it by calling empty refresh with props after delay
Actions.popTo('pageOne');
setTimeout(() => {
Actions.refresh({name:'zzzzar'});
console.log("zzzz");
}, 10);

@washaq: That did the trick for me

@ronyv89 glade it work for u can any one help me on this? "https://github.com/facebook/react-native/issues/9280"

Actions.pop(); Actions.refresh();
just refresh the page but does not go to previous scene.

It would be nice if Actions methods could be promised based so you can chain them together like

Actions.pop().then(Actions.refresh()).

or

Actions.pop().refresh()

@israrhnrtech and @tuneZola its not working if you want to call refresh of previous then u need to call it after delay then it will called properly like that

Actions.pop();
setTimeout(() => {
Actions.refresh({name:'zzzzar'});
console.log("zzzz");
}, 10);

First of all Thanks for the Reply @tuneZola and @washaq .
Actions('pageOne');
setTimeout(() => {
Actions.refresh({name:'zzzzar'});
console.log("zzzz");
}, 10);

this code is working very well ..
thanks again ..

@israrhnrtech no problem dude i find that really lot of hit and trail lol its looks simple know but when u r new on react native and doesn't know how to do that then its different story :)

I'm facing this same problem, on my Scenes:

A => B

on B I change my redux store state, but when I do a Router.pop(), componentWillReceiveProps is not triggered on A.

My router.pop lives locally inside the B page (not using default navBar), so

Router.pop()
Router.refresh()

does not work, setting a timeout does not work either, any ideas on how to achieve this?

i will only update when you pass your props that you want to change i.e

Actions.pop();
setTimeout(() => {
Actions.refresh({name:'zzzzar'});
console.log("zzzz");
}, 10);

in this i pass name as props in my main view that means if i m using this.props.name to update text then its updated you need to pass updated state as a props in refresh because thats how view know its updated.
Hope this will help you

For me applying this worked:
navigator.replacePreviousAndPop(previousRoute);

@phpscrpt , can you brief more with some codes that how its working ?

@israrhnrtech sorry it is for react-native's built in Navigator component. If react-native-router-flux is inherited from the Navigator component somehow it may work.

@washaq The timeout solution, as implemented below, is not working for me:

backAndRefresh(){

Actions.pop();
setTimeout(() => {
Actions.refresh({name:'zzzzar'});
console.log("zzzz");
}, 10);

}

GO BACK AND REFRESH

The componentDidMount on the page I want to refresh is not being called.

Am I missing something?

Thanks!

@ivansifrim did you found a solution for this?
we're also trying to find a way to trigger an action after landing on the screen

This works for me: Actions.pop({ refresh: {} });
It pops the current screen and refreshes the parent screen.

@JeroenNelen - I haven't yet but I'll try what @Bertjuhh suggested

Any solution for the problem mentioned ?

This is working well for me:

const refreshOnBack = () => { Actions.pop({ refresh: {} }); }
...
// child scene
<Scene key="settings" component={SettingsScreen} onBack={refreshOnBack}/>
...

In a simple app I've recently done I've worked around this like so (this code is in my router file above the export):

Actions.pop = () => Actions.NAME_OF_PREVIOUS({ type: ActionConst.RESET });

You'll have to do some conditional logic in the function you're using to override pop. Worked beautifully in my case (granted I don't mind the alternate back transition while using ActionConst.RESET). Quick n nasty.

Is there finally anything working well here ? None of the propositions above are really working...

+1

@ivansifirm it should be working last I used it remember in refresh pass the props you want to undate I.e above 'name' is the props that I want u update in my previous view

same issue here, very strange.
sometimes it works, sometimes it doesn't work.

Here is my code. (In my case, there are scene A and B, A=>B by navigating, B=>A by poping)

Scene A:
componentWillReceiveProps(nextProps) { if (this.props.test !== nextProps.test) { this._getUser() // I need call this func after pop } }
Scene B

NavigationActions.pop({refresh:{test:true}})

What's wrong with me ?
Thanks.

NavigationActions.pop({refresh:{test:true}})

can you change it to

NavigationActions.pop({refresh:{test:!test}})

On Tue, Jun 20, 2017 at 7:29 PM, MobileStar notifications@github.com
wrote:

same issue here, very strange.
sometimes it works, sometimes it doesn't work.

Here is my code. (In my case, there are scene A and B, A=>B by navigating,
B=>A by poping)

Scene A:

componentWillReceiveProps(nextProps) {
if (this.props.test !== nextProps.test) {
this._getUser() // I need call this func after pop
}
}

Scene B

NavigationActions.pop({refresh:{test:true}})

What's wrong with me ?
Thanks.


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/aksonov/react-native-router-flux/issues/465#issuecomment-309945049,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AExqB3CZM4U1yuwKslfuBj88uVVJulGtks5sGIAbgaJpZM4H_0pN
.

@nikitph Thanks for your help.
Yeah, I tried with it.
But componentWillReceiveProps doesn't fire always after pop.
Could you possibly let me know when componentWillReceiveProps is fired or there is a other lifecycle func is fired after pop ?
Regards.

@SelfnessAid ahh now i remember why i gave up on solving this issue. i had a similar problem. "But componentWillReceiveProps doesn't fire always after pop." I think i have worked around it by having the index of a swipeable view which i have on the target page drive the refresh. yes it sucks but i m getting my problem solved.

I figured something out. I don't really think it is clean at all but for me it does the job, so here it is. (I'm using Redux to do this)

I needed to call a fetch function whenever I did an Action.scene() or Action.pop(). This fetch was initially called in the componentWillMount method but as it isn't called when using Action.pop() I changed all my Action.scene() and Action.pop() calls to 2 custom functions which are actions which means that I have more redux containers than I normally should but eh :/. So here they are:

const goTo = (scene, label, sceneParams = {}, pushed = true) => ( // Equivalent of `Action.scene()`
   (dispatch) => {
     dispatch(setAppLabel(scene, label, sceneParams, pushed)); // I'm storing some infos about the scene in my store. Will be used in custom `pop()` later.
     mapSceneToAction(scene, dispatch, sceneParams); // // Calls the function initially used in the componentWillMount. I'll show a sample further
     Actions[scene](sceneParams);
   }
);

const pop = () => (  // Equivalent of `Action.pop()`
   (dispatch, getState) => {
     Actions.pop();
     mapSceneToAction(getState().sceneReducer.previousScene, dispatch, getState().sceneReducer.previousScene.itemProps); // Retrieving some infos stored in the store during `goTo()`
   }
);

And here is how mapSceneToAction() looks like:

const mapSceneToAction = (scene, dispatch, itemProps) => {
  switch (scene) {
    case 'events':
      dispatch(fetchEvents()); // Or any other action :P
      break;
    case 'anyScene':
      dispatch(anyAction(withAnyParams));
      break;
    default:
  }
};

It is a bit tricky, heavy and probably not really clean but since I'm using this method I've managed to fix all the problems I had.

Pass a function prop to the next scene..
Actions.YourRoute({ onPress: () => setState.. });

Then on the next scene, call the function prop
this.props.onPress();

@bethuel11 This is re rendering the component in a loop. Not a good solution though

i found simple trick...

current state / current page =>

Actions.pop();
setTimeout(() => {
Actions.refresh({
isRefresh: true,
});
}, 0);

pervious state / page => inside render add below condition,

if(this.props.isRefresh){
Actions.refresh({
isRefresh: false,
});
//if u call set state here it will automatically rerender itself...
this.setState({isloading:true});

Thanks.
}

Was this page helpful?
0 / 5 - 0 ratings

Related issues

YouYII picture YouYII  ·  3Comments

GCour picture GCour  ·  3Comments

jgibbons picture jgibbons  ·  3Comments

rafaelcorreiapoli picture rafaelcorreiapoli  ·  3Comments

sylvainbaronnet picture sylvainbaronnet  ·  3Comments