Show loading when navigate from one view to another in react native - react-native

I am on React native 0.29 for android. I used navigator in my app so that user can navigate from one view to another. I want to know is there any way I can show a loading symbol when navigator is navigating from one view to another.

I assume that the reason you're navigation is delayed is because you're fetching data asynchronously to prepare the next view. This answer isn't going to be very helpful if you've just got a performance concern.
Anyway, I've followed this basic pattern, basically I set the loader to true, then after I have the data, I set the loader to false and pass the data along to the view as a prop.
_handleLogin() {
this.setState({
isLoading: true,
},
() =>
Api.getUser( username, password )
.then( user => this._handleResponse( user ))
);
}
_handleResponse( user ){
this.setState({
isLoading: false,
})
this.props.navigator.push({
title: 'Home',
component: Home,
passProps: {
user: user,
}
});
}

Related

Remove listener AppState change react native

Good evening everyone, I am facing a problem.
I am developing an app in react-native and I need that, every time a user sends the app in the background or in an inactive state, when he returns to the app I force him to go to a certain screen (Loading) where I perform certain checks (such as if he is a blocked user, deleted, etc ...).
I have now written the following function
const [appState, setAppState] = useState(AppState.currentState);
useEffect(() => {
getAttivita();
getBanner();
const appStateListener = AppState.addEventListener(
"change",
(nextAppState) => {
setAppState(nextAppState);
if (nextAppState === "active") {
navigation.dispatch(
CommonActions.reset({
index: 0,
routes: [{ name: Routes.Loading }],
})
);
}
}
);
return () => {
appStateListener?.remove();
};
}, []);
I put this listener in the Screen Diary (which represents my home).
Now if from the screen Diary, I minimize the app, then I have no problems and everything works as it should.
However if I go to another screen and minimize the app, then I get the following error
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
in Diary (at SceneView.tsx:122)
Then when I log back into the app I realize that the listener for the app status is still active (so it is as if the remove () had not worked) and in fact I am pushed back into my loading screen.
So I'm wondering, is it the listener that isn't actually being removed?
Or am I doing something wrong?
Thanks in advance to who will answer me .

React Native Navigation: Navigate to a screen from outside a React component

https://wix.github.io/react-native-navigation/docs/basic-navigation#navigating-in-a-stack
indicates that pushing a new screen to the stack requires the current screen's componentId. My use case is to allow navigating based on certain events emitted by a native module. As such, componentId won't be available to me, since the event listener would reside outside any React component screen. Is there any way to navigate to a screen from outside in RNN? Or even get the current componentId.
I ended up adding a command event listener to store the current componentId in closure.
let currentComponentId;
Navigation.events().registerCommandListener((name, params) => {
if (name === 'push') {
currentComponentId = params.componentId;
}
});
Navigation.events().registerAppLaunchedListener(() => {
Navigation.setRoot(rootRouteConfig);
EventEmitter.addListener('navigate', (name) => {
Navigation.push(currentComponentId, {
component: {
name,
},
});
});
});

How to hide TabNavigator dynamically on React Native

So i have an app with react native navigator, what I plan for my app is to show a Tutorial when the user first launches the app, I use react-copilot for it, it works really great, but the problem is, React copilot takes time to initiate, and it launches BEFORE the react-navigator.
The problem is that the user can click the navigator thus breaking the tutorial or even crashing the system because the tutorial did not initiate properly.
I plan to make the navigator to be disabled dynamically when the tutorial not yet started. Here's the snippet of the code from the navigationOptions on the appNavigation
TabMenu.navigationOptions = ({ navigation, screenProps }) => {
const childOptions = getActiveChildNavigationOptions(navigation, screenProps);
return {
title: childOptions.title,
tabBarVisible: childOptions.tabBarVisible,
header: null
};
};
and here's the static value on the component
static navigationOptions = {
tabBarVisible: false
}
It works, but the problem is when the tutorial ends and I set the static value to true, the tabBar doesn't appear. Is there any way around this?
Thank you in advance
EDIT :
i need to clarify that what i need is to make the tabbar appear and dissapear within the same page after certain activity (in this case tutorial) finished without the need to reload/navigate to the same page
It's like Gabriel answer
static navigationOptions = ({ navigation, screenProps }) => {
const { tabBarVisible = true } = navigation.state.params
? navigation.state.params
: {};
return {
tabBarVisible: tabBarVisible
};
};
Place the navigation options inside any Tab Item and update the tabBarVisible property like this.
this.props.navigation.setParams({
tabBarVisible: false
});
I would try putting all the tutorial from react-copilot into a different page which is not inside the bottom navigation bar or maybe even in a Modal (which by default cover the whole application).
After the react-copilot instructions are done you are free to navigate to the bottom navigation bar or dismiss the Modal.
NEW SUGGESTION AFTER COMMENT:
I think you could change some values in the navigationOptions by doing the following:
static navigationOptions = ({ navigation }) => {
return {
headerTitle: navigation.getParam('title', ''),
}
};
and then in a function inside the component calling the following:
this.props.navigation.setParams({ "title": 'brand new name') })
This works for me on an app where I had to change the header title of a page after a button was clicked. But I'm not sure if that would work with the attribute tabBarVisible. Would you mind giving it a try?

How to pass data from one component to Navigator and from Navigator to component

I'm actually doing a login system and when my user is logged, the login component has to send data to my main screen but I don't really understand how to do it.
Actually I've this when user is logged :
User.username = data.username;
User.id = responseJson.id;
User.token = responseJson.token;
this.props.navigation.navigate('Main', { User: User });
User is where everything is saved and it works.
Data is sended to Main a Switch Navigates inside an AppContainer :
export default createAppContainer(createSwitchNavigator(
{
Auth: { screen: AuthStack, navigationOptions: { tabBarVisible: false } },
Main: { screen: MainStack },
},
{
initialRouteName: "Auth"
}),
);
so it goes on Mainstack who's a bottomTabNavigator and works like that :
const MainStack = createBottomTabNavigator(
{
Services: {
screen: Home,
navigationOptions: {
tabBarLabel:"Services",
tabBarIcon: ({ tintColor }) => (
<Icon name="home" size={30} color="#0033CC" />
)
},
},
I know it's not complete I've other screens not only Services, just wanted to avoid too long function on paste.
So is that possible to send this data "User" to my Home screen ?
I'm open to any suggestion or answer, that's my first react Native project so there is maybe some mistakes :)
You'll probably want to persist the user data in the app (save it in the storage for when the user leaves the app then enters he stays logged in). That's why react-navigation has the switchNavigator (the one you are using). In order to persist data, you can use the AsyncStorage to save the user data and in the switch navigator constructor check whether the user data is already available in the storage or not then decide whether to navigate to the app or the authentication page. In fact React Navigation provides an example on this: https://reactnavigation.org/docs/en/auth-flow.html . Since you're new to RN, here's an extra tip on managing data: you can use a State in every component that is only for that specific component (which is also reactive), you can use global data (store) shared between all the components in the app (check react redux/flux/mobx), you can share data from parent components to children components by passing data/functions in the props (aka attributes), and you can use the new React context api to use a provider (also like a store shared between parent and children components)
I've made something maybe a bit more understandable :
I get my user data in component login from an external api and it works well. To go from login to home I'm using this :
this.props.navigation.navigate('Main', { User: User})
So it goes on Main who opens Mainstack Screen who's a bottomTabNavigator and if I don't do any mistakes my User data that I've sent is on this Mainstack but I don't know how to get it and how to share it to the other components.
Every component got his own js file, there is only the App container and Authstack/Mainstack that are on the same file.
Hope you understood it !

react-navigation doesnt work with react-native-lightbox

I am writing a project that navigates using react-navigation and i want to use lightbox however lightbox requires Navigator to function properly. I was hoping to see if i could write react-navigation support into the component and then allow a PR to happen. The possibility in my mind is using Navigator + react navigation so that i dont have to re-make my navigation because you could have both "this.props.navigator" and "this.props.navigation" but i am not sure how some of the navigation and navigator functions work.
I have been looking into lightbox.js at the occurences of Navigator and i am searching through the react-navigation api to see if i can find replacements for the functions used as it only occurs 8 times (2 of which are just checks to see if navigator is present).
lightbox.js - navigator occurences
open: function() {
this._root.measure((ox, oy, width, height, px, py) => {
this.props.onOpen();
this.setState({
isOpen: (this.props.navigator ? true : false),
isAnimating: true,
origin: {
width,
height,
x: px,
y: py,
},
}, () => {
if(this.props.navigator) {
create a route that will work with navigation (for react-navigation it would be the navigationOptions)
var route = {
component: LightboxOverlay,
passProps: this.getOverlayProps(),
};
fetch the current set of routes
var routes = this.props.navigator.getCurrentRoutes();
push a route onto the stack
routes.push(route);
some sort of reset for the stack that Navigator does (still looking into it, any help knowing what this does would be nice.
this.props.navigator.immediatelyResetRouteStack(routes);
Then the rest of the code for opening the lightbox runs
} else {
this.setState({
isOpen: true,
});
}
this.setTimeout(() => {
this.state.layoutOpacity.setValue(0);
});
});
});
},
for closing the stack the same lines are called but with .pop() instead of .push()
Anyone with experience of both react-navigation and react-native-lightbox would be a great help.