Change ex-navigation bar title after component was mounted - react-native

Ex-navigation allows defining navigation bar title using static route
static route = {
navigationBar: {
title: 'title'
}
}
I'd need to set navigationBar title programmatically after the component was mounted since it depends on data received from a server. How can I do it?
I've tried using props.route.config, but that only works when called in componentDidMount() but not later in component lifecycle.
this.props.route.config.navigationBar.title = 'new title'

Use the updateCurrentRouteParams as described here in the doc
:
class ProfileScreen extends React.Component {
static route = {
navigationBar: {
title(params) {
return `Hello ${params.name}`;
}
}
}
callMeLatter() {
this.props.navigator.updateCurrentRouteParams({name: "Jon Doe"})
}
}

Related

How to create an Authentication middleware for a Flutter app?

This is my home.dart code and I want to write an Authentication Middleware for my app. At the moment my main.dart code looks like this:
void main() {
Get.put(MenuController());
Get.put(NavigationController());
Get.put(AuthController());
Get.put(AuthCard);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Obx(() => GetMaterialApp(
initialRoute: AuthController.instance.isAuth
? homeScreenRoute
: authenticationScreenRoute,
unknownRoute: GetPage(
name: '/not-found',
page: () => PageNotFound(),
transition: Transition.fadeIn),
getPages: [
GetPage(
name: rootRoute,
page: () {
return SiteLayout();
}),
GetPage(
name: authenticationScreenRoute,
page: () => const AuthenticationScreen()),
GetPage(name: homeScreenRoute, page: () => const HomeScreen()),
],
debugShowCheckedModeBanner: false,
title: 'BasicCode',
theme: ThemeData(
scaffoldBackgroundColor: light,
textTheme: GoogleFonts.mulishTextTheme(Theme.of(context).textTheme)
.apply(bodyColor: Colors.black),
pageTransitionsTheme: const PageTransitionsTheme(builders: {
TargetPlatform.iOS: FadeUpwardsPageTransitionsBuilder(),
TargetPlatform.android: FadeUpwardsPageTransitionsBuilder(),
}),
primarySwatch: Colors.blue,
),
));
}
}
And the isAuth variable that I checking at the initialRoute part of the code comes from the following line of codes, inside the auth_controller file that extends GetXController:
final _isAuth = false.obs;
bool get isAuth {
_isAuth.value= token != null;
return _isAuth.value;
}
String? get token {
if (_expiryDate != null &&
_expiryDate!.isAfter(DateTime.now()) &&
_token != null) {
return _token;
}
return null;
}
Everything seems good but the application sticks at the authentication page and won't move to home screen after the isAuth's value changed to true!
I searched for that and found another way by creating an authentication middleware. So I added the following code bellow the above code inside the main.dart file:
class AuthMiddlware extends GetMiddleware {
#override
RouteSettings? redirect(String route) => !AuthController.instance.isAuth
? const RouteSettings(name: authenticationScreenRoute)
: null;
}
But I get a red line under the redirect word with no error decription and don't know how to complete the middleware and make it work?
Example of how to implement an AuthGuard with FirebaseAuth and Getx.
(If not using FirebaseAuth, swap it to your preferred authentication provider in AuthGuardMiddleware.)
middleware.dart
import 'auth.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class AuthGuardMiddleware extends GetMiddleware {
var authService = Get.find<AuthService>();
#override
RouteSettings? redirect(String? route) {
return authService.isLoggedIn() ? null : RouteSettings(name: '/login');
}
}
auth.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:get/get.dart';
class AuthService extends GetxService {
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
bool isLoggedIn() {
return _firebaseAuth.currentUser != null;
}
// IMPLEMENT additional FirebaseAuth methods here.
}
main.dart
import 'package:get/get.dart';
import 'middleware.dart';
...
GetPage(
name: '/protected',
page: () => Protected()),
middlewares: [
AuthGuardMiddleware(),
]),
...
Copy paste :)
class AuthMiddlware extends GetMiddleware {
#override
RouteSettings? redirect(String? route) => !AuthController.instance.isAuth
? const RouteSettings(name: authenticationScreenRoute)
: null;
}

React Native - Adding logic to Stack Navigation

I have the following Stack Navigation:
const WelcomeStack = createStackNavigator({
UpdateProfileScreen: {
screen: UpdateProfileScreen,
},
SelectProfileScreen: {
screen: SelectProfileScreen,
},
PresentationModal: {
screen: PresentationModal,
}
}, {
initialRouteName: 'UpdateProfileScreen',
headerMode: 'none'
})
When a user is new, I show "UpdateProfileScreen" first, then I move to "SelectProfileSecreen" and then "PresentationModal".
If for some reason after "UpdateProfileScreen" user closes the app, next time they log in I will show "SelectProfileSecreen" and "PresentationModal". If they complete data, next time, they will only see the "PresentationModal"
Since I have set "UpdateProfileScreen" as initialRoute, it will always load first, even if it does not show.
So I was wondering if programatically I could change the initialRoute and/or if I do:
this.props.navigation.navigate("WelcomeStack")
I can add some logic in the same stack to handle the page to show?
I think your best option is using SwitchNavigator(RouteConfigs, SwitchNavigatorConfig) you can simply create it with createSwitchNavigator as it controls all the switching of navigators used mainly for authentication flow in most react native apps.
With that said, for your case i think its the most suitable way to achieve the desired behavior.
Please be careful if publishing an app using something along the lines of :
this.props.navigation.navigate("WelcomeStack")
as it can be a serious security vulnerability
docs: https://reactnavigation.org/docs/1.x/switch-navigator/
snack example: https://snack.expo.io/#react-navigation/auth-flow
I had a similar problem here how i resolved it:
Added SwitchNavigator like so:
let Navigation = createSwitchNavigator(
{
AuthLoading: AuthLoading,
LoginNavigator: LoginNavigator,
HomeNavTab: tabNavigator,
LoggedInChose: LoggedInChose
},
{
initialRouteName: "AuthLoading"
}
);
The AuthLoading stack is the first to load and decides where the app go next:
import React from "react";
import { connect } from "react-redux";
class AuthLoading extends React.Component {
constructor(props) {
super(props);
this.checkUserSession();
}
checkUserSession = () => {
const userData = this.props.userData;
if (userData) {
const residencesNumber = userData.nbreResidences;
if (residencesNumber == 1) {
this.props.navigation.navigate("HomeNavTab");
} else {
this.props.navigation.navigate("LoggedInChose");
}
} else {
this.props.navigation.navigate("LoginNavigator");
}
};
// Render any loading content that you like here
render() {
return (
null
);
}
}
const mapStateToProps = state => {
return {
userData: state.userData
};
};
export default connect(mapStateToProps)(AuthLoading);
Maybe you get an idea from this.

React Native Navigation 5.x NavigationInjectedProps

I am currently switching to navigation 5.x from 4.x. I'm using
import { NavigationInjectedProps } from 'react-navigation'
across the entire application, but I cannot find anything equivalent in navigation 5. I'm using typescript.
Could anyone lead me in the right direction?
First of all, the logic behind obtaining params is changed. In v5, you have to access them from a route, which is passed as an additional property for class components, unlike using navigation in the previous versions.
To type your params in the right way, you have to type the route. For previously written code:
import { NavigationInjectedProps } from 'react-navigation'
type Params = {
param1: string
}
type Props = NavigationInjectedProps<Params>
class MyComponent extends Component<Props> {
render() {
const { param1 } = this.props.navigation.state.params
}
}
the rough equivalent will be:
import { StackScreenProps } from '#react-navigation/stack'
type RootParamsList = {
MyComponent: {
param1: string
}
}
type Props = StackScreenProps<RootParamsList, 'MyComponent'>
class MyComponent extends Component<Props> {
render() {
const { param1 } = this.props.route.params.param1
return null
}
}

How to set navigation params properly

I use react-navigation for navigation in my app. I have some modal view (SomeComponent) and I wanna set custom title during presenting animation. The problem is that title is changing but after presenting animation is finished.
I've tried set params in other component lifecycle callback but it didn't work.
I don't want to set this parameter with navigate function because I don't have full data to set it.
class SomeComponent extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
title: navigation.getParam("customTitle"),
}
}
componentDidMount() {
this.props.navigation.setParams({ customTitle: "Some custom title" })
}
}
I wanna set title before animation is finished.
Try to set the params in the getDerivedStateFromProps method as this is the method that is fired after the constructor and before any render methods

Navigation - Pass variable to other files

I'm new on React-Native and it's my first React-Native app. However, I have already some problems.
I want to pass a variable from one class (Home.js) to an another. (Is it possible without using the composent in the render() fonction ?)
##### Home.js #####
class Home extends Component {
constructor(props) {
super(props);
this.state = {direction: "defaultvalue"};
}
getCurrentDirection() {
return this.state.direction;
}
render() {
/***..... some elements ..*/
}
}
export default Home
And
#### Two.js ####
import Home from './Home'
/** SOME CODE **/
const DrawerOptions = {
initialRouteName: Home.getCurrentDirection(),
contentComponent: CustomDrawerContentComponent,
drawerWidth: 300,
};
However it doesn't work... How to resolve it ? I have already try some solutions as declare the getCurrentDirection as static but nothing.
In addition, it seems to be a specific case because DrawerOptions is not a class. Could you please, add to your response also, how make it if I want to obtain the variable into the class Two.js ?
I meant if Two.js was for example :
##### Two.js #####
class Two extends Component {
var myvariable = Home.getCurrentDirection();
render() {
/***..... some elements ..*/
}
}
Thanks a lot in advance
A recommendable way of accessing the state from a component into another is to use (in this case) the Home component as a parent of Two component. This way you don't have to trigger a function to access the Home's state. On each time when the state of the parent (in this case) component will be updated, the Two component will receive the updated property (direction). If you want to call a function from Two component, you have to pass it a function as a property (changeCurrentDirection) that will call back the function you want to trigger from Home component.
So you would have something like this:
class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
direction: "defaultValue"
};
}
changeCurrentDirection() {
this.setState({
direction: "valueChanged"
})
}
render() {
let state = this.state;
return (
<Two
direction={state.direction}
changeCurrentDirection={() => this.changeCurrentDirection.bind(this)}/>
)
}
}
class Two extends React.Component {
render() {
let props = this.props;
return (
<div>
<h3>{props.direction}</h3>
<button onClick={props.changeCurrentDirection()}>Change value</button>
</div>
)
}
}
React.render(<Home/> , document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.0/react.min.js"></script>
<div id="app"></div>
Additional info you can find here.
Also, if you want to have a good management of the state of your components, my advice for you is to use redux. Using this library you can easily connect the component's actions and properties that can further be accessible from other files where you can manage them.