Null is not an object while creating navigation between screens in expo project - react-native

I need to open new screen after clicking on the button. For it I made the following steps:
1) Installed this library
2) Created a new screen and added it to the folder with other screens (DetailInfoScreen is a new screen, which should be opened and HomeScreen is a screen, where a button, after clicking on which new screen should be opened):
3) Added the following lines of code:
import { Navigation } from 'react-native-navigation';
import DetailInfoScreen from './DetailInfoScreen';
class HomeScreen extends Component {
constructor(props) {
super(props);
this.onPressSearch = this.onPressSearch.bind(this);
Navigation.registerComponent('DetailInfoScreen', () => DetailInfoScreen);
}
goToScreen = (screenName) => {
Navigation.push(this.props.componentId, {
component: {
name: screenName
}
});
}
render() {
const { list, text } = this.props;
return (
<View style={styles.container}>
<View style={styles.searchContainer}>
<TouchableOpacity
onPress={this.goToScreen('DetailInfoScreen')}
>
<View>
<Text>Search</Text>
</View>
</TouchableOpacity>
</View>
);
}
But when I run the project I have the following error:
And one more moment which disturbs me is that autocorrection in vscode doesn't see my new screen while importing:
Maybe it doesn't play any role, but still. So, what's the reason of the problem and how can I solve it?

You can simply navigate to another screen by using this:
<TouchableOpacity
onPress={() => this.props.navigation.navigate('DetailInfoScreen')>
<Text>Search</Text>
</TouchableOpacity>

I would personally advice for you to use react-navigation instead of react-native-navigation, you can read more on this link

Related

React Native - Variable link using a prop

I'm making an app with some products that I got from my Wordpress database. On the homescreen, I have an overview of all the products, each in a tile. I want to be able to put a button in each tile, which links to the specific product page. But, since it works with a component, I need to be able to do this with a prop. And, if possible, based on the title of the API.
This is my code for the screen with all the products:
import React, { useState, useEffect } from 'react';
import { StyleSheet, Text, View, FlatList, Image, Button } from 'react-native';
import SuitcaseItem from '../components/SuitcaseItem';
const AllSuitcasesScreen = ({ navigation }) => {
const [suitcases, setSuitcases] = useState([]);
const getSuitcases = async () => {
try {
const response = await fetch("https://evivermeeren.com/wp-json/wp/v2/posts?categories=59", {
}
)
const json = await response.json();
console.log(json);
setSuitcases(json);
} catch (error) {
console.error(error);
}
}
useEffect(() => {
getSuitcases();
}, []);
return (
<View style={styles.screen}>
<View style={styles.flexbox2}>
<Text style={styles.products}>Onze koffers</Text>
<View style={styles.shoppingcart}>
<Image
style={styles.icon}
source={{uri: 'https://cdn-icons-png.flaticon.com/512/1413/1413908.png'}}
/>
<Text style={styles.number}>0</Text>
</View>
</View>
<View style={styles.list}>
<FlatList
data={suitcases}
renderItem={({ item }) => (
<SuitcaseItem
title={item.title.rendered}
imageUri={{uri: 'https://www.samsonite.be/on/demandware.static/-/Sites/default/dw851ab6f0/images/misc/sams_share-image.jpg'}}
desc={item.slug}
buttonText={item.title.rendered}
/>
)}
/>
</View>
</View>
);
}
export default AllSuitcasesScreen;
And this is the result:
Now, when I click the black button, I go to the page 'Evo L', which I also made. This is the button that I use:
<Pressable style={styles.seeProduct} onPress={() => navigation.navigate("Evo L")}>
<Text style={styles.text}>Bekijk product: {props.buttonText}</Text>
</Pressable>
This is in another file, the 'SuitcaseItem'.
So, I should be able to put something like navigation.navigate("props.buttonNav") with buttonNav = {item.title.rendered} so it goes to the page Evo L if I click on that one and then Evo M when I click on that tile and so one. Does anyone have an idea?
You can pass props to a screen. See this excellent official documentation for React Navigation on passing props.
-> Make a generic item detail screen like ItemDetail (instead of Evo L).
-> Modify the navigation.navigate("props.buttonNav") to:
navigation.navigate("ItemDetail", {itemTitle: props.buttonText})
You can access these props in the ItemDetail screen as:
function ItemDetail({ navigation, route }) {
return(
<Text>route.params.itemTitle</Text>
)
}

How to reparent a component in ReactNative?

In the below code, I expected the webView content to not change when the clicks are increased, but every time it loads, a new timestamp is displayed.
const webView = (
<WebView
source={{
uri:
'data:text/html,<html><script>document.write("<h1 style=\\"font-size:64px\\">"+Date.now()+"<h1>");</script>',
}}
/>
);
export default class App extends React.Component {
state = {
clicks: 0,
};
onClick = () => {
this.setState({ clicks: this.state.clicks + 1 });
};
render() {
return (
<View>
<Text onPress={this.onClick}>
Click Me: {this.state.clicks}
</Text>
{this.state.clicks % 2 === 0 ? webView : null}
{this.state.clicks % 2 === 1 ? webView : null}
</View>
);
}
}
Link to expo snack to check it on a device.
So far, I've read about reparenting in React on issues here, implementing using Portals, and also saw an issue on supporting reparenting in react native with no resolution.
So, how to reuse a component instance in across multiple screens with out creating a new instance of it in every screen?
Was hoping reparenting would be the answer, but can't find any implementations, so if reparenting is the answer to this, how to implement it myself?
The problem here is that on every state change your component will re-render webView object and will show the current date. I suggest that you change webView to a component and add a static key when you call WebViewComp to prevent unmount/mount on every state change.
const WebViewComp = () => ( //Change declaration to function component instead of constant object
<WebView
source={{
uri:
'data:text/html,<html><script>document.write("<h1 style=\\"font-size:64px\\">"+Date.now()+"<h1>");</script>',
}}
/>
);
export default class App extends React.Component {
state = {
clicks: 0,
};
onClick = () => {
this.setState({ clicks: this.state.clicks + 1 });
};
render() {
return (
<View style={styles.container}>
<Text style={styles.paragraph} onPress={this.onClick}>
Click Me: {this.state.clicks}
</Text>
{this.state.clicks % 2 === 0 ? <WebViewComp key="child" /> : null}
{this.state.clicks % 2 === 1 ? <WebViewComp key="child" /> : null}
</View>
);
}
}
You definitely need to reparenting the view. I searched some libs that work as React Portals does.
We have two projects available:
https://github.com/zenyr/react-native-portal
https://github.com/mfrachet/rn-native-portals
I tested the second package (rn-native-portals) and this magically worked on Android:
How to install
npm install mfrachet/rn-native-portals
react-native link (unfortunately we can't auto-link this yet, but we can submit PR)
Implementation
Your target element needs to be inside <PortalOrigin>
import React from "react";
import { View, Text, TouchableOpacity } from "react-native";
import { PortalOrigin } from 'rn-native-portals';
class Target extends React.Component {
state = {
moveView: false,
}
render() {
return (
<>
<TouchableOpacity
style={{ flex: 1 }}
onPress={() => this.setState({ moveView: !this.state.moveView })}
>
<Text>Press Here</Text>
</TouchableOpacity>
<PortalOrigin destination={this.state.moveView ? 'destinationPortal' : null}>
<View>
<Text>This text will appear on destination magically...</Text>
</View>
</PortalOrigin>
</>
);
}
}
export default Target;
On destination use this (don't forget set the same unique portal's name)
import React from "react";
import { PortalDestination } from "rn-native-portals";
class Destination extends React.Component {
render() {
return (
<PortalDestination name="destinationPortal" />
);
}
}
export default Destination;
This project is amazing, but definitely need our community help to create a better documentation.
I have one project that need to use this feature, reparenting a video to the outside of screen. I'm seriously considering PR auto-link support to avoid compiling warnings.
More useful info about:
The project concept:
https://github.com/mfrachet/rn-native-portals/blob/master/docs/CONCEPT.md
Why the project was created (long history):
https://tech.bedrockstreaming.com/6play/how-a-fullscreen-video-mode-ended-up-implementing-react-native-portals/
Haven't tried the accepted answer's projects but, for React Native, #gorhom/portal works like a charm retaining context like a champ!

React Native: Not smooth scrolling with DrawerNavigator

Current Behavior
My code:
class App extends Component {
render() {
return <Drawer /> {/* rigid scrolling effect */}
return <Stack /> {/* smooth scrolling effect if I comment above return statement */}
}
}
const Drawer = DrawerNavigator({
Feed: { screen: Feed }
})
const Stack = StackNavigator({
Feed: { screen: Feed }
})
And Feed component's render is just a bunch of lines:
render() {
return <View style={{flex:1}}>
<ScrollView>
<Text>random line...</Text>
// .. more lines to make it scrollable
</ScrollView>
</View>
}
Expected Behavior
The expected behavior is to get smooth scrolling effect in both cases. However, DrawerNavigator screen's scrolling effect is extremely rigid. When I swipe my finger quickly from up to down, it doesn't keep scrolling smoothly automatically like it should in Stacknavigator example.
How to reproduce
Create App.js file above and create a simple Feed.js component which has a bunch of lines to make ScrollView work.
Can anybody help?
Update: Live demonstration: https://snack.expo.io/Hk8Np7nPG
Try this
render() {
return (
<View style={{flex:1}}>
<ScrollView>
<View>
{Your Contnet}
</View>
</ScrollView>
</View>
)}
it is worked for me...
hope it'll also worked for you
You can Use NativeBase with standard tabs Container and Contet (like ScrollView ) Header and...
first try :
npm install native-base --save
then:
npm i
react-native link
and here is your full example code:
import React, { Component } from 'react';
import { Content , View , Text } from 'native-base'; //don't need import 'react-native' components
export default class GeneralExample extends Component {
render() {
return (
<Content >
<View>
{Your Contnet}
</View>
</Content>
)}
}
and if you wanna change the speed just ScrollView try:
<ScrollView decelerationRate={0.5}>
<View/>
</ScrollView>
in NativeBase Use THIS LINK

React Native - Push one Screen To Another have issue

I used the 'StackNavigator', I have issue to push when navigation code write in button event. but its working fine if we directly code onPress event,
Import file.
import { StackNavigator } from "react-navigation";
import SignUpScreen from "./SignUp";
Push another is working :
render() {
console.disableYellowBox = true;
const { navigate } = this.props.navigation;
return (
<View style={styles.viewStyle}>
<TouchableHighlight style = {styles.buttonStart}
onPress={() => navigate("SignUpCompany")}>
<Image
source={require('./Images/hire.png')}
/>
</TouchableHighlight>
</View>
);
}
Push another via function is not working :
pushcode() {
console.log('call');
this.props.navigation.navigate('SignUp');
}
render() {
return (
<TouchableHighlight style = {styles.buttonStart}
onPress={this.pushcode}>
<Image
source={require('./Images/hire.png')}
/>
</TouchableHighlight>
);}
ERROR ON CLICK BUTTON :
Thanks. Please help me.
Look like you are using the push extra in this line
this.props.navigation.navigate.push('SignUp');
Try this will work for you
this.props.navigation.navigate('SignUp');
May be this can help you
I think you miss the function bind within constructor --- that's why you got undefined is not an object (evaluating 'this.props.navigation'). because this is undefined inside pushcode function scope.
add below into your constructor:
constructor(props) {
super(props);
this.pushcode = this.pushcode.bind(this);
...
}

undefined is not an object(evaluating 'this.props._navigate.replace/push')

I'm new to React Native and trying ( followed a tutorial ) to move to another screen when a button is clicked, this is the updated code I have and a photo of the error I get when pressing the button.
index.ios.js:
export default class Application extends Component {
constructor(){
super();
}
renderScene(route, navigator){
if(route.name == 'login'){
return <Login navigator={navigator}/>
}else if(route.name == 'home'){
return <Home navigator={navigator}/>
}
}
render() {
return <Navigator
initialRoute={{name: 'login'}}
renderScene={this.renderScene.bind(this)}/>
}
}
LoginForm:
export default class LoginForm extends Component{
constructor(props){
super(props);
this.navigate = this.navigate.bind(this);
}
navigate(routeName){
this.props.navigator.replace({
name: routeName,
Component: Home
});
}
render(){
return(
<View style={mStyle.container}>
<StatusBar barStyle='light-content'/>
<TouchableOpacity>
<Text style={mStyle.btnText}>
LOGIN WITH FACEBOOK
</Text>
</TouchableOpacity>
<TouchableOpacity onPress={()=>this.navigate('home')}>
<Text style={mStyle.noLoginTxt}>
CONTINUE WITHOUT LOGIN
</Text>
</TouchableOpacity>
</View>
);
}
}
I'm trying to move from login screen to home screen when button is clicked.
I get this problem when pressing the button on the emulator:
A couple of problems that you are facing.
1.- The syntax is:
this.props.navigator.{any_method}
Such as:
this.props.navigator.push
this.props.navigator.replace
Not
this.props._navigate.{any_method}
2.- If you have child views make sure you are sending to the childs the Navigator property such as.
<View>
<MyChildComponent navigator={this.props.navigator} />
</View>
3.- Make sure your child view gets the props from the parent on the constructor.
Change
constructor(){
super();
this._navigate = this._navigate.bind(this);
}
To
constructor( props ){
super( props );
// The following line is not required since you are using an arrow function to call this one.
// this._navigate = this._navigate.bind(this);
}
It is because there is a mismatch between property you use in Navigator and in your component
Change
_navigate(name){
this.props._navigate.replace({ //I also tried push, same problem.
name
});
}
to
_navigate(name){
this.props.navigator.replace({ //I also tried push, same problem.
name
});
}