React Native Navigation 5.x NavigationInjectedProps - react-native

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
}
}

Related

Mobx React Reactivity with Hooks and Observer

I've updated the app to use Mobx-react 6 along with Mobx state tree.
I'm not able to get the latest value inside the component when I use custom store hooks.
import { observer, MobXProviderContext, useObserver } from 'mobx-react';
function useStores() {
return useContext(MobXProviderContext);
}
function useJob() {
const { jobStore } = useStores();
return useObserver(() => jobStore);
}
//USAGE
function ChildDocs(props) {
const jobStore = useJob();
const { validChildDocuments, setCurrentChildDoc, currentChildDoc, noneDocuments } = jobStore;
//This won't update although the value in the store is null after re-mount. This shows the old value
console.log('verificationDataStore=', currentChildDoc.verificationDataStore);
}
export default observer(ChildDocs);

How to susbscribe to property on the state in Vue?

I have vue application.
I'm using vuex and vuex-class packages to connect with the store.
in my component(vue-property-decorator) I want to subscribe to some property on the state, and when it change then I want to know.
for example:
my state for example:
const state = {
error: null,
};
and getters:
const getters = {
error(state: any) {
return state.error;
},
};
my component:
import { Component } from 'vue-property-decorator';
import { namespace } from 'vuex-class';
const SomeModule = namespace('somemodule');
#Component({})
export default class MyPage extends SomeBaseComponent {
#SomeModule.Getter('error')
error: any;
// HOW TO know when error has change?
}
onErrorChanged() {
//?????
}
I want onErrorChanged will fire every time the error property on the state changed.
How to do that?
I'm a maintainer of vue-property-docorator. Thanks for using the library.
If you'd like to observe the changes of error property, you can do it by $watch.
As you are using vue-property-decorator, #Watch decorator is available.
#Component({})
export default class MyPage extends SomeBaseComponent {
#SomeModule.Getter('error')
error: any;
#Watch('error')
onErrorChanged(newErrorVal, oldErrorVal) { }
}

Using React-native-notifications in React-navigation

I have an app with following structure:
AuthNavi: {
login1: login1,
login2: login2
}
TabNavi: {
tab1: TabNavi1
tab2: TabNavi2,
...
}
AppSwitchNavi: {
AuthLoading: LoadingScreen, (initial screen)
Auth: AuthNavi,
Content: TabNavi
}
The app started with AppSwitchNavi, if haven't login the app, it will go to AuthNavi, else go to TabNavi.
I would like to add request the notification permission after login, and handling of notification may also be added after login.
Does anyone know how to implement notification in at this situation, which only works in TabNavi?
This is the simple event-based implementation on components.
import { EventEmitter } from 'events';
const appEvents = new EventEmitter();
appEvents.setMaxListeners(0);
export default class AppEvents {
static removeEvent(subscribe) {
subscribe.remove();
}
static registerLoginEvent(method) {
return appEvents.addListener('Login-Required-Event', method);
}
static emitLoginEvent(data) {
appEvents.emit('Login-Required-Event', data);
}
static removeLoginEvent(method) {
appEvents.removeListener('Login-Required-Event', method);
}
}
Implemetation:
import React from 'react';
import AppEvents from './AppEvents';
import AppSwitchNavi from './Navigations';
export default class AppSwitchNaviWrapper extends React.Component {
componentDidMount() {
AppEvents.registerLoginEvent(this.loginEvent);
}
componentWillUnmount() {
AppEvents.removeLoginEvent(this.loginEvent);
}
loginEvent = () => {
// do something
};
render() {
return <AppSwitchNavi />;
}
}
Emit event from some situation as AppEvents.emitLoginEvent(UserData);
But IMO you should handle redux for such situations, Redux will help you out in long run. The event-based implementation makes problem to you & you have to very careful about the implementation and removing the event to prevent memory leaks and unexpected behavior of the app.

Inheritance of Angular 5 components with overriding the decorator properties

In Angular 2/4 we could create custom decorator for extending parent component. Actual overriding of the decorator properties was handled as needed in the custom decorator. To get parent annotations we used:
let parentAnnotations = Reflect.getMetadata('annotations', parentTarget);
After update to Angular 5 this doesn't work anymore. Regarding this
answer we could use:
target['__annotations__'][0] for getting parent component annotations.
In order to set annotations in the current component in Angular 2/4 we used:
let metadata = new Component(annotation);
Reflect.defineMetadata('annotations', [ metadata ], target);
How can set current component annotations in Angular 5?
At the end I came up to this implementation of a custom decorator (extendedcomponent.decorator.ts):
import { Component } from '#angular/core';
export function ExtendedComponent(extendedConfig: Component = {}) {
return function (target: Function) {
const ANNOTATIONS = '__annotations__';
const PARAMETERS = '__paramaters__';
const PROP_METADATA = '__prop__metadata__';
const annotations = target[ANNOTATIONS] || [];
const parameters = target[PARAMETERS] || [];
const propMetadata = target[PROP_METADATA] || [];
if (annotations.length > 0) {
const parentAnnotations = Object.assign({}, annotations[0]);
Object.keys(parentAnnotations).forEach(key => {
if (parentAnnotations.hasOwnProperty(key)) {
if (!extendedConfig.hasOwnProperty(key)) {
extendedConfig[key] = parentAnnotations[key];
annotations[0][key] = '';
} else {
if (extendedConfig[key] === parentAnnotations[key]){
annotations[0][key] = '';
}
}
}
});
}
return Component(extendedConfig)(target);
};
}
Example usage:
First implement the parent component as usual (myparent.component.ts):
import { Component, Output, EventEmitter, Input } from '#angular/core';
#Component({
selector: 'my-component',
templateUrl: 'my.component.html'
})
export class MyParentComponent implements OnInit {
#Input() someInput: Array<any>;
#Output() onChange: EventEmitter<any> = new EventEmitter();
constructor(
public formatting: FormattingService
) {
}
ngOnInit() {
}
onClick() {
this.onChange.emit();
}
}
After that implement child component which inherit the parent component:
import { Component, OnInit } from '#angular/core';
import { ExtendedComponent } from './extendedcomponent.decorator';
import { MyParentComponent } from './myparent.component';
#ExtendedComponent ({
templateUrl: 'mychild.component.html'
})
export class MyChildComponent extends MyParentComponent {
}
Note: This is not officially documented and may not work in many cases. I hope that it will help somebody else, but use it at your own risk.

Change ex-navigation bar title after component was mounted

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"})
}
}