Comments (2)
Today, when we add a will/didFocus listener on a screen, if that screen is currently focused, the listener will fire.
can you provide a snack that demonstrates clearly what is happening here?
from rfcs.
Hi @brentvatne
TLDR
I was not totally correct in all my assumptions above.
The following seems to apply to willFocus and didFocus
Infinite loop.
When using declarative event comp or hooks, it's simpler to unsub/resub, but this can easily lead to the following:
componentDidMount() {
this.props.navigation.addListener('willFocus', () => {
this.incrementCounter();
this.props.navigation.addListener('willFocus', () => {
this.incrementCounter();
});
});
}
Counter = 2, but I think in such case it should be counter = 1, which would solve the infinite loop problem. Redux had a similar issue too.
Breaking change would be small and may be considered as a bug.
Do we really want willFocus on mount?
When mounting the initial navigation, on the initial route names, without any animation etc, do we really want focus events to fire? What are the usecases for this? This complicates the usecase where you want to refresh api data on focus, because it might lead to a double fetch on mount.
More important breaking change, but with clear migration path possible.
Details
Infinite loop.
Here is a snack that shows the infinite loop problem the current solution can actually trigger: https://snack.expo.io/@slorber/focus-event
The original issue reporting this is react-navigation/react-navigation#5058
This loop happens because:
- The listener triggers a state change
- We unsub/resub on every update
- The resub triggers the listener
My snack may feel convoluted and the unsub/resub unnecessary, but when using declarative approachs like or hooks, particularly when providing closures as listeners, it's important to ensure the last closure provided is run because a closure capture external variables at creating time, and those variables may change over time. Unsub/resub permits to easily ensure the last closure is run.
Actually I think my initial description of the problem is not totally correct. It seems unsub/resub happening inside a "didFocus" is actually the problem. The button in the snack does show that when the screen is already focused, and we add a listener, this listener will actually not be fired even if the screen is focused (where I was wrong).
As far as I remember, Redux had this issue too and solved it by creating a listener array copy before iterating on them, so that on resub, the newly added listener won't be executed before next focus. Doing something similar can make sense here to ensure that we don't encounter any infinite loop.
The following should only print 1 imho, currently it prints 2: https://snack.expo.io/@slorber/focus-event-2
Do we really want willFocus on mount?
This would solve the infinite loop issue, but would not solve the issue where the user might not necessarily want this listener to fire on mount (because it may be wired to a "refresh api data" method)
For me the main usecase to willFocus
was mostly to track focused screen before, but we have better alternatives now (withNavigationFocus, navigation.isFocused()...). The main usecase that remains for me is to refresh api data on screen focus. But generally the tools we use already do the fetching on mount (like Apollo) so having this event firing will trigger a "double fetch" on mount. Do we really want this event to fire when the initial navigator screen is mounting?
I don't know how users are using this listener, maybe my assumptions are incorrect, and it would be a larger breaking change.
from rfcs.
Related Issues (20)
- Action property that indicates to routes that they should not change index HOT 1
- Improve ergonomics of back HOT 1
- Navigator config to pass params down HOT 1
- Add unsetParams to navigation prop HOT 2
- Reset state action HOT 2
- Expose logic for initializing state of createAppContainer HOT 4
- Idea: Preloading HOT 6
- <StaticNavigator> for tests/storybook HOT 14
- StackActions.popToRouteName(routeName) HOT 2
- Alternative API for defining navigators HOT 12
- how to send navigation events between peer navigators? HOT 4
- Deep linking with authentication
- How to hide tab bar item n react-navigation HOT 3
- Ability to show screens on top of native modals
- useNavigationParams hook HOT 1
- Add useMaterialTabsHeight HOT 1
- Typesafe Stack & Navigation HOT 1
- devTools prop HOT 5
- [RFC] TabView API change
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from rfcs.