React Native Navigation - startTabBasedApp - only load tab if clicked on - react-native

When using startTabBasedApp(params) in React Native Navigation (by Wix), all of the tabs load at once.
Is there a way to make it so that only the initial tab loads? And then only after clicking on another tab does that tab load?

I don't believe it's possible. See this comment for more information, it seems like they intended this behaviour.

A possible workaround is to use the following within the component:
onNavigatorEvent(event) {
switch (event.id) {
case "bottomTabSelected":
this.setState({ didPressTab: true })
break
case "willAppear":
ApplicationScreensManager.getInstance().registerCurrentActiveScreen(ApplicationScreens.WebViewContainerScreen)
}
break
}
}
while this case "bottomTabSelected": is fired only when selecting a tab, then you can set the state raising a flag and only then do whatever you intended on when pressing the tab.
good luck

Related

How to determine mouse events in React Native (mobile)?

I need to use a callback function for the mouse click event. Below code is working in React web app:
const checkAnswer = (e: React.MouseEvent<HTMLButtonElement>) => {
const answer = e.currentTarget.value // here .value property is undefined and gives error in React-Native. Just e.currentTarget is defined.
const correct = questions[number].correct_answer === answer
if(correct) setScore(prev => prev + 1)
}
But I couldn't apply it on React Native (mobile) for Pressable or TouchableOpacity.
This is the render part of React web app's code:
<button value={answer} onClick{checkAnswer} />
and I try to apply it on React Native. The value will be passed to button's value. But there is no "value" option in native's Pressable component. Therefore I am confused
Any help?
you can determine touch events by following
<View onTouchStart={(e) => {console.log('touchMove',e.nativeEvent)}} />
Here is some similar scenario what I could able to understand from the question.
There is a Score state which will store the user's score of a quiz game.
There is a array of question where all the options and correct option are given.
There will be a button for the option, if user choose a option, and based on that it will validate if user is correct or not.
It might not be the exact scenario of you. But this could definitely help to solve your scenario.
Here is a solution for the scenario => solution.
If you click on the solution link you will be redirect to a page which is similar to the screenshot attached below. On very right you will find "My Device", "Android", "ios", choose any and run. Run via "my device" with expo app installed in your mobile if you don't want to be in queue for some certain time.
Note: from your code this is for React web:
<button value={answer} onClick{checkAnswer} />
but in React Native you have to use a click event like this:
<TouchableOpacity onPress={()=>buttonHandler()}></TouchableOpacity>
Here ()=> and () extra need to be added to work a function properly.
Also instead of .map() function you can use FlatList to improve your app. FlatList support lazy loading.

Reload previous screen in React Native

I've been using this way to refresh the previous screen when triggering a button from the current screen.
Screen A
constructor(props){
...
this.handleOnNavigateBack = this.handleOnNavigateBack.bind(this);
}
handleOnNavigateBack = (foo) => {
this.setState({ foo })
}
goToScreenB(){
this.props.navigation.navigate('ScreenB', {
onNavigateBack: this.handleOnNavigateBack
})
}
Screen B
goBackToScreenA(){
this.props.navigation.state.params.onNavigateBack(this.state.foo)
this.props.navigation.goBack()
}
I need to keep the function inside the parameters first so that it can be triggered when going back from screen b. But this is okay to use if it is from 1 screen to 1 screen. If I have a multi layer screen been navigated such as
from Screen A -> Screen B -> Screen C,
and go back
from Screen C -> Screen B -> Screen A then reload the function at Screen A, it will be troublesome.
Or maybe the situation is :
from Screen A -> Screen B, then from Screen B replace Screen C, then from Screen C -> Screen A then only reload the function at Screen A.
By doing so, I have to keep passing the function to reload when every navigation taken place. So I was wondering if there is a way to capture the screen entered and fire the specific function that you want like how Ionic did.
In Ionic case, there is an event called ionViewWillEnter where it helps to perform this reloading thing without going through with the function registration and all. You simply call out the function and that's it.
I've been trying to find a way that is working similar to this at React Native but I can't have it work around. I've heard about redux but never implement it as I still can't understand how it works so I'm trying not to use it first.
Based on your question you are looking for something similar to 'ionViewWillEnter' which will run a callback whenever a screen is focused.
Given that you are using React Navigation v5
The hook useFocusEffect serves the same purpose of running a function whenever a screen is focused this includes navigating back to a screen as well.
From the documentation
Sometimes we want to run side-effects when a screen is focused. A side
effect may involve things like adding an event listener, fetching
data, updating document title, etc. While this can be achieved using
focus and blur events, it's not very ergonomic.
The code would be something like this
useFocusEffect(
React.useCallback(() => {
alert('Screen focused')
// Do something when the screen is focused
return () => {
alert('Screen was unfocused');
// Do something when the screen is unfocused
// Useful for cleanup functions
};
}, [])
);
You can find the documentation here
https://reactnavigation.org/docs/use-focus-effect/
If your requirement is updating the data by passing something from screen B or C you can think of using Context which is easy to use or if you are planning to to use redux that is also a possible alternative.

Trigger function/event whenever changing tab in Wix Navigation v2

I wanted to run a function whenever I change to a specific tab in my react-native app, but I couldn't find a way.
I know that after Wix Navigation (RNN) v2, the way to change current tab is by using mergeOptions, and that works. But what if I want to also, after the tab is changed, execute a function from that screen?
This is how I'm changing the tab:
Navigation.mergeOptions(this.props.componentId, {
bottomTabs: {
currentTabIndex: 3
}
}
The tab is changed, but I couldn't find a way to add a listener or trigger event after this specific event occurs.
Is there any way to accomplish this?
React-Native: 0.60.5
React-Native-Navigation: 3.1.2
Thanks.
You can add a listener which will trigger when ever the tab change . See Documentation
Try this
// Subscribe
const bottomTabEventListener = Navigation.events().registerBottomTabSelectedListener(({ selectedTabIndex, unselectedTabIndex }) => {
});
...
// Unsubscribe
bottomTabEventListener.remove();

How to prevent changing the screen when using "this.props.navigation.navigate"?

I'd like to pass the values from Tab to another Tab and I follow instructions from this tutorial https://reactnavigation.org/docs/en/params.html
I got the values at the end but i don't want to change the screen suddenly.
I tried to use 'setParams' instead but it doesn't work.
Setting tab (Selection) :
onPress={() => {
console.log('Select : '+ item.code);
this.props.navigation.navigate('A-page', {adCode: item.code});
}}
First tab (A-page) :
this.setState ({
AirportCode : this.props.navigation.getParam('adCode','----')
})
Any ideas for passing values across Tab navigation or method to stop changing the screen suddenly?
This looks more like a Redux use case then a React Navigation one. If you wanna change properties that influence more than one screen in your app, you should store these properties at the redux store.

How to navigate to a different view that is not a child?

I am new to react native and new to iOS (not programming) so please excuse me if this question is a simple one. I am trying to navigate from one view to another (with a transition), however they are not related so I do not need the back navigation. I actually do not have a navigation bar at all. When using the Navigator component it seems to not support this at all. I am not sure if there is a separate way to do this but I am not able to figure it out without implementing my own hack.
If I use the navigator component and keep pushing on the views then it just keeps them all in memory and I do not want that. I can transition from one view to another and then pop but I may end up going to the wrong view in that case. I can also replace the view but it seems that does not allow for transitions.
To give you a scenario think of it like this:
Application starts and loads a "Loading" screen.
When initial loading is complete it will then go to the "Login" screen.
There is a button on the "Login" screen to "Register" or "Retrieve Password".
If they click "Register" it will take them there with a button back to "Login".
If they click "Retrieve Password" it will take them to a page with buttons to go back to "Login" or "Register".
So by this example you can see that there is no way to pop because if you were on the login screen and went to the register screen and then wanted to go the retrieve password screen then pop just simply wouldn't work. I do not want any navigation controls on the screen I just want to be able to do a smooth transition between these screens.
Now I was able to find a way to do this but I had to add a method to the Navigator class and hack code in using some of there core methods which seems like its not a good idea at all but here is the code (note this is really just a hack to see if it would work):
Navigator.prototype.pushWithUnmount = function(route) {
var activeLength = this.state.presentedIndex + 1;
var activeStack = this.state.routeStack.slice(0, activeLength);
var activeAnimationConfigStack = this.state.sceneConfigStack.slice(0, activeLength);
var nextStack = activeStack.concat([route]);
var destIndex = nextStack.length - 1;
var nextAnimationConfigStack = activeAnimationConfigStack.concat([
this.props.configureScene(route),
]);
this._emitWillFocus(nextStack[destIndex]);
this.setState({
routeStack: nextStack,
sceneConfigStack: nextAnimationConfigStack,
}, () => {
this._enableScene(destIndex);
this._transitionTo(
destIndex,
null, // default velocity
null, // no spring jumping
() => {
this.replaceAtIndex(nextStack[destIndex], 0);
this.setState({
presentedIndex: 0,
});
}
);
});
}
By using the code provided above I am now able to do:
this.props.navigator.pushWithUnmount({ component: SomeComponent });
With this code the views are pushed onto the stack with a transition and the old views are unmounted when its finished.
Please tell me that I am doing something wrong and that there is a better way to do this?
The default router with React Native is pretty limited. I'd check out React Native Router Flux. We just switched to it a few weeks ago in our product and have really liked it. It does exactly what you want.