Odd behavior in passed params with React Navigation - react-native

Here's the screen:
import React from 'react';
import { View, StyleSheet, Image, TouchableOpacity, Text } from 'react-native';
import { NavigationActions } from 'react-navigation'
export default class ContentScreen extends React.Component {
render() {
const { state } = this.props.navigation;
const { code } = state.params.code
return(
<Text>CONTENT GOES HERE: {JSON.stringify(state)} / '{code}'</Text>
)
}
}
And the navigation invocation:
<TouchableOpacity key={k} onPress={() => {navigate("Content", {code: k})}} style={styles.listing}>
And here's what's displayed:
CONTENT GOES HERE: {"params":{"code":"222"},"key":"id-151010...","routeName":"Content"} / ''
Which is really #(#$ weird. The value clearly exists at state.params.code, as can be seen by the JSON string, and yet when accessed, it isn't present. Object.values(state.params) and Object.keys(state.params) give the expected results (["code"] and ["222"]).
So, like, any ideas as to what's going on? Or ideas about how to further investigate?

Looks like you are destructuring one level too deep.
const { code } = state.params.code;
This is basically looking for this.props.state.params.code.code
Try:
Const { code } = state.params;
Or:
const { navigation: { state: { params: { code } } } } = this.props;

Related

Screen Refresh Issue in React Native

I am making an app that uses firestore. Whenever a data changes in firestore my screen shows two set of data i.e. one set with data before change and other after the change.
for example if I have two data a,b and b is updated to c then the screen shows a,b a,c
After toggling between two screen, the screen gets refreshed and things become okay.
How to get the screen show only new set of data
Any help?
import React,{Component} from 'react';
import { View,ScrollView,AsyncStorage, StyleSheet, Dimensions, SafeAreaView,Platform,StatusBar,Text,Alert,Button,FlatList,TouchableOpacity} from 'react-native';
import {db} from "./FirebaseCon.js";
import firebase from "firebase";
import {useNavigation} from "#react-navigation/native";
import "firebase/firestore";
export default class NoticeList extends React.Component
{
constructor(props)
{
super(props);
this.state={Notice:[],myuser:"",setFlag:null};
}
componentDidMount()
{
let notice=[];
var d=new Date();
var pbm="";
const notref=db.collection("Notice");
async:notref.where("expiry",">=",new Date()).orderBy("expiry","desc").onSnapshot(querySnapshot=>
{
querySnapshot.forEach(doc=>
{
this.setState({Notice:notice});
notice.push(doc.data());
this.setState({Notice:notice});
}
)
});
}
render()
{
const getuser=async()=>
{
let uname=await AsyncStorage.getItem("username");
this.setState({myuser:uname});
this.setState({setFlag:true});
}
if(this.state.setFlag==null)
{
getuser();
}
let myusername=this.state.myuser;
return(
<ScrollView style={nstyles.scene} >
{
this.state.Notice.map(data=>{
const n1=data.expiry.toMillis()-86400000;
const o1=new Date();
const p1=new Date(n1);
let time=p1.getDate();
if(p1.getDate()==o1.getDate())
{
time="Today, ";
}
else
{
time="Yesterday, ";
}
time+=""+p1.getHours();
time+=":"+p1.getMinutes();
const formtmsg=data.message+"\n\n Published By : \n"+data.pby+"\n\n In Order Of :\n"+data.oby
if(data.pby!=myusername)
{
return(
<TouchableOpacity style={nstyles.notlist} onPress={()=>Alert.alert("Notice",formtmsg)}>
<Text style={nstyles.publisher}>{data.oby}<Text style={nstyles.ptime}>{"\n"+time}</Text></Text>
</TouchableOpacity>);
}
})
}
<Text style={{color:"grey",fontSize:16,alignSelf:"center"}}>Published By You</Text>
{
this.state.Notice.map(data=>{
const n=data.expiry.toMillis()-86400000;
const o=new Date();
const p=new Date(n);
let time=p.getDate();
if(p.getDate()==o.getDate())
{
time="Today, ";
}
else
{
time="Yesterday, ";
}
time+=""+p.getHours();
time+=":"+p.getMinutes();
const formtmsg=data.message+"\n\n Published By : \n"+data.pby+"\n\n In Order Of :\n"+data.oby
if(data.pby==myusername)
{
return(
<TouchableOpacity style={nstyles.notlist2} onPress={()=>Alert.alert("Notice",formtmsg)}>
<Text style={nstyles.publisher}>{data.oby}<Text style={nstyles.ptime}>{"\n"+time}</Text></Text>
</TouchableOpacity>);
}
})
}
</ScrollView>);
}
}
Divyansh Dixit, when dealing with lists React uses the key prop of the component in order to re-render the screen.
Your issue can be fixed by adding a unique key prop to the component returned by your map function, in your case the <TouchableOpacity>
It would look something like this
<TouchableOpacity key={data.id}>
...
</TouchableOpacity>
You can read more about this on https://reactjs.org/docs/lists-and-keys.html#gatsby-focus-wrapper

null is not an object (evaluating 'this.nativeCommandsModule.push')

I am using WIX-React-Native-Navigation and while pushing a component in the stack I am getting this error.
Error
One thing to say, I am using Viro-React ARScene Navigation (Scene Navigation) in WIX-React-Native-Navigation.
Here's my code
index.js
import { AppRegistry } from 'react-native';
var OpenDoor = require('./app/base')
import Stack from './app/navigation';
import { Navigation } from "react-native-navigation";
AppRegistry.registerComponent('ViroSample', () => OpenDoor);
Navigation.events().registerAppLaunchedListener(() => {
Navigation.setRoot({
root: {
stack: Stack
}
});
});
navigation.js
import { Navigation } from "react-native-navigation";
import Base from './base';
import Menu from './components/Menu/menu';
Navigation.registerComponent('Base', () => Base);
Navigation.registerComponent('Menu', () => Menu);
const Stack = {
children: [{
component: {
name: 'Base'
},
}
]
};
export default Stack;
base.js
import React, {Component} from 'react';
import {
Alert,
View
} from 'react-native';
import {ViroARSceneNavigator} from 'react-viro';
import { Navigation } from 'react-native-navigation';
import APIKeys from './index';
import Camera from './components/Camera/camera';
import MenuButton from './components/Menu/menu_button';
class Base extends Component {
constructor(props) {
super(props);
this.navigateScreen = this.navigateScreen.bind(this);
}
navigateScreen(location) {
Navigation.push(this.props.componentId, {
component: {
name: location
}
});
}
render() {
return(
<View style={styles.container}>
<ViroARSceneNavigator
initialScene = {{
scene: Camera
}}
apiKey = {APIKeys.ViroReact}
style = {styles.ar_scene}
/>
<MenuButton navigation={this.navigateScreen}/>
</View>
);
}
};
const styles = {
container: {
flex: 1
}
};
export default Base;
module.exports = Base;
Correct me, If I am wrong somewhere.
What I am doing is, creating an application where users can decorate home virtually with the help of Augmented Reality. The mobile app is created on React-Native while the library used for augmented reality is Viro-React.
So, When I want to navigate from One Screen to another, then while pushing component in the stack I am getting this error.
Thanks.

getting duplicate navigation options at the top

I am showing a list of services on my page. I am using react-navigation. Somehow, I see two navigation bar on the top of my phone. Below is the image:
I just want the top most navigation bar. I don't want the second one. I looked at my code several times, but could not find the error. I am not sure what am I doing wrong that I am seeing duplicate navigation bar. Below is my code:
import React, { Component } from 'react';
import { Text, View, StyleSheet, ListView, ActivityIndicator, TextInput, TouchableOpacity } from 'react-native';
import { Provider, connect } from 'react-redux';
import { createStore } from 'redux'
import reducers from '../reducers/ServiceReducer';
import ServiceItem from './ServiceItem';
import Icon from 'react-native-vector-icons/EvilIcons';
import ServiceDetail from './ServiceDetail';
import { StackNavigator } from 'react-navigation';
import ServiceListDetails from './ServiceListDetails' ;
class AutoCompActivity extends Component {
constructor(props) {
super(props);
this.state = {
// Default Value of this State.
Loading_Activity_Indicator: true,
text:'',
selected_topic_id: -1,
}
this.arrayholder=[];
}
componentDidMount() {
const data = require('../reducers/services.json')
let ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.setState({
Loading_Activity_Indicator: false,
dataSource: ds.cloneWithRows(data),
}, function() {
// In this block you can do something with new state.
this.arrayholder = data ;
});
}
SearchFilterFunction(text){
const newData = this.arrayholder.filter(function(item){
const itemData = item.ser.toUpperCase()
const textData = text.toUpperCase()
return itemData.indexOf(textData) > -1
})
this.setState({
dataSource: this.state.dataSource.cloneWithRows(newData),
text: text
})
}
ListViewItemSeparator = () => {
return (
<View
style={{
height: .5,
width: "100%",
backgroundColor: "#000",
}}
/>
);
}
clickedItemText( clickedItem )
{
this.props.navigation.navigate('Item', { item: clickedItem , navigationOptions:{header:null}} );
}
static navigationOptions =
{
title: 'testing'
};
render()
{
// this is my render code. I can put the render code if someone wants to see it.
}
export default MyNewProject= StackNavigator(
{
First: {screen: AutoCompActivity},
Item: {screen: ServiceListDetails, navigationOptions:{header:null}},
}
any help will be greatly appreciated.
Hmm, it's tough to tell what's going on here. Where you have this:
static navigationOptions =
{
title: 'testing'
};
try changing it to this:
static navigationOptions =
{
header: null,
};
There are a couple places you can disable or define the header from. One is in the component itself, and one is in the second parameter of StackNavigator().
For example, you could have this:
export default MyNewProject = StackNavigator(
{
First: {screen: AutoCompActivity},
Item: {screen: ServiceListDetails},
},
{
navigationOptions: {
header: null,
}
}
)
Or you could have this:
class AutoCompActivity extends Component {
static navigationOptions = {
header: null,
}
render() {
// ...
}
}
I was just reading this article here last night. You may find it helpful in seeing some different aspects you aren't using yourself currently: https://hackernoon.com/how-to-use-a-custom-header-and-custom-bottom-tab-bar-for-react-native-with-react-navigation-969a5d3cabb1
Based on what I see here, try header: null in the second parameter Object of StackNavigator. I have a feeling one of the headers will go away but for that whole stack. It's really confusing. I sometimes hate it myself, but it is good for supporting composition once you find a pattern you like.
My wording here might be confusing. I'm saying null them all out until you can gain a handle on it.

undefined is not an object this.props

I try to use navigation between screen in my RN app. This is my code :
INDEX.ANDROID.JS :
import React, { Component } from 'react';
import {
AppRegistry,
Text,
View ,
Button
} from 'react-native';
import {StackNavigator} from 'react-navigation';
import Login from './app/components/Todo';
const SimpleApp = StackNavigator({
Login: { screen: Todo },
});
export default class aap extends Component {
static navigationOptions = { title: 'Welcome', };
render() {
const { navigate } = this.props.navigation;
return (
<Button onPress ={() => navigate('Todo') } title="go"/>
);
}
}
AppRegistry.registerComponent('aap', () => aap);
here is the code of the second screen TODO.JS
import React, { Component } from 'react';
import {
AppRegistry,
Text,
View ,
Button
} from 'react-native';
export default class Todo extends Component {
render() {
return (
<View>
<Text>
Here is my text
</Text>
</View>
);
}
}
When running my code i get an error : undefined is not an object this.props.naviagtion.
Any help is appreciated
You are not using StackNavigator correctly.
Like #xght said, you should be registering SimpleApp instead of aap. Also, you should be using aap as the initial route to your StackNavigator SimpleApp.
This should look something like this:
import React, { Component } from 'react';
import {
AppRegistry,
Text,
View ,
Button
} from 'react-native';
import {StackNavigator} from 'react-navigation';
import Todo from './app/components/Todo';
class aap extends Component {
static navigationOptions = { title: 'Welcome', };
render() {
const { navigate } = this.props.navigation;
return (
<Button onPress ={() => navigate('Todo') } title="go"/>
);
}
}
const SimpleApp = StackNavigator({
Login: { screen: aap },
Todo: { screen: Todo },
});
AppRegistry.registerComponent('aap', () => SimpleApp);
You registered the wrong component, so the navigator SimpleApp doesn't pass the navigation prop to your component.
Replace
AppRegistry.registerComponent('aap', () => aap); by:
AppRegistry.registerComponent('aap', () => SimpleApp);
And also you forgot to add your aap component in SimpleApp routes. And your import Login from './app/components/Todo';is wrong: Login is the name of the route in SimpleApp, and Todo is the name of the component, so you need to replace it by import Todo...

Headless Task use inside component with React Native

I am trying to run a background task using headlessjs in react-native. The problem is that I am unable to access the async task inside the component in order to show it on the view. Here's my default component.
import React, { Component } from 'react';
import {
AppRegistry,
Text,
View,
NativeModules
} from 'react-native';
module.exports = NativeModules.ToastAndroid;
someTask = require('./SomeTaskName.js');
export default class test2 extends Component {
constructor() {
super()
this.state = {
myText: 'My Original Text'
}
}
updateText = () => {
this.setState({myText: 'My Changed Text'});s
}
componentDidMount(){
this.setState({myText: someTask});
someTask.then(function(e){ //<--- error
console.log("lala" + e);
});
}
render() {
return (
<View>
<Text>
abc
</Text>
</View>
);
}
}
AppRegistry.registerComponent('test2', () => test2);
AppRegistry.registerHeadlessTask('SomeTaskName', () => someTask);
As mentioned in the code, I get the error undefined is not a function. I don't know how to make this work. My SomeTaskName.js looks like this.
SomeTaskName.js
module.exports = async (taskData) => {
return taskData.myname;
}
The idea is to simply get the data from the service and show it on the UI.
The solution was to simply move the code inside the componentDidMount function. Here's how I achieved it.
/**
* Sample React Native App
* https://github.com/facebook/react-native
* #flow
*/
import React, { Component } from 'react';
import {
AppRegistry,
Text,
View,
Image
} from 'react-native';
export default class test2 extends Component {
constructor() {
super()
this.state = {
myText: '1'
}
}
componentWillUnmount() {
}
componentDidMount(){
someTask = async (taskData) => {
this.setState({ myText: taskData.myname});
}
};
}
render() {
return (<Text>Working</Text>);
}
}
AppRegistry.registerHeadlessTask('SomeTaskName', () => someTask);
AppRegistry.registerComponent('test2', () => test2);
You can replace :
someTask = require('./SomeTaskName.js');
by
import SomeTaskName from './SomeTaskName'