undefined is not an object (evaluating 'this.handleMapView.bind') - reactjs

I have been trying to binds methods to the class with no success. I think am doing everything right, as explained in the documentation. I have also tried other binding plugins but all in vain kindly help.
The weird thing is that, if I bind directly from the render method it works but the moment i try calling a method from another method hell brakes loose.
import React, { Component } from 'react';
import { Navigator, NetInfo, View } from 'react-native';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { ActionCreators } from '../actions';
import _ from 'underscore';
import Api from '../utils/api';
import FooterView from '../components/footer';
import { Container, Content, Icon,
Badge,Footer, FooterTab, Header,
Title, Card, CardItem,Text,
Spinner, List, ListItem, Tabs, Button } from 'native-base';
import theme from '../stylesheets/theme';
import Communications from 'react-native-communications';
function mapStateToProps(state) {
return {
currentUser: state.currentUserReducers,
};
};
function mapDispatchToProps(dispatch) {
return bindActionCreators(ActionCreators, dispatch);
};
class ClientDirectory extends Component {
constructor(props){
super(props);
}
renderCustomers(){
let { currentUser, isLoading } = this.props;
var customers = _.map(currentUser.customers, function(customer){
return(
<Card style={{padding: 1}}>
<CardItem header>
<Text>Shop Name: { customer.name }</Text>
</CardItem>
<CardItem cardBody>
<Text>
Name: { customer.manager_first_name } { customer.manager_last_name }{"\n"}
Region: { customer.region_name }{"\n"}
Landmark: { customer.landmark }{"\n"}
Phone Number: { customer.phone_number }
</Text>
</CardItem>
<CardItem style={{flex:1, alignItems: 'center', justifyContent: 'center', }} header>
<Button transparent style={{ flex:1 }} onPress={ () => Communications.phonecall(customer.phone_number, false)}><Icon name='ios-call' /></Button>
<Button transparent style={{ flex:1 }} onPress={ () => Communications.text(customer.phone_number)}><Icon name='ios-chatboxes'/></Button>
<Button transparent style={{ flex:1 }} onPress={ this.handleMapView.bind(this) }><Icon name='ios-compass' /></Button>
</CardItem>
</Card>
);
});
return customers;
}
handleMapView(){
let { navigator } = this.props;
navigator.push({
name: 'ViewOnMap',
});
}
render(){
return (
<Container>
<Header>
<Button transparent>.</Button>
<Title>Bonus client list</Title>
<Button transparent>
<Icon name='ios-menu' />
</Button>
</Header>
<Content style={{padding: 10, marginBottom:10}}>
{ this.renderCustomers() }
</Content>
</Container>
);
}
};
export default connect(mapStateToProps,mapDispatchToProps)(ClientDirectory);
just to mention, I have tried the below with no luck
http://moduscreate.com/using-es2016-decorators-in-react-native/
https://www.npmjs.com/package/autobind-decorator
Any help will be highly appreciated.
Thanks.

This worked.
var _this = this;
http://javascriptplayground.com/blog/2012/04/javascript-variable-scope-this/

Move your bindings to the constructor like this:
constructor(props){
super(props);
this.handleMapView = this.handleMapView.bind(this);
}
And then your onPress callback should look like this:
onPress={ this.handleMapView }

Related

How to navigate between screens with StackNavigator if I have different js files for each screen?

fairly new to React Native. I have read the stack navigator docs and still don't get how to do this.
So I have a bottom tab navigator, and I want to implement a stack navigator in one of the tabs, so I can navigate from the main tab screen to the second screen, but from the second screen to third screen I cannot navigate as it can't find the variable "navigation", which is understandable because I'm using different js files for each screen. How do I pass over the navigation variable to the other screen? Below is my code:
OrderScreen.js:
imports...
import { createStackNavigator } from '#react-navigation/stack';
const Stack = createStackNavigator();
const styles = StyleSheet.create({
...
}
});
function Orderscreen({ navigation }) {
return (
<View style={styles.welcome}>
<View styles={styles.container}>
<Button style={styles.button1} color="warning" uppercase onPress={() => { navigation.navigate('Scan QR code') }}><Text style={styles.buttonText}>Take me to screen SCAN QR CODE</Text></Button>
</View>
</View>
)
};
import { Qrcodescanner } from './qrcodescanner';
import { Menu } from './menu';
import { render } from 'react-dom';
function MenuScreen({ navigation }) {
return(
<Menu></Menu>
)
}
function QRScanScreen({ navigation }) {
return(
<Qrcodescanner></Qrcodescanner>
)
}
export default function App() {
return (
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={Orderscreen} />
<Stack.Screen name="Scan QR code" component={QRScanScreen}
options={{
headerRight: () => (
<Button shadowless
onlyIcon icon="question" iconFamily="antdesign" iconSize={30} color="info" iconColor="#fff" style={{ width: 35, height: 35, marginRight: 20 }}
/>
),
}}
/>
<Stack.Screen name="Menu" component={MenuScreen} />
</Stack.Navigator>
);
}
Qrcodescanner.js:
export class Qrcodescanner extends React.Component {
...
render() {
const { hasCameraPermission, scanned } = this.state;
if (hasCameraPermission === null) {
return <Text> Requesting for camera permission </Text>;
}
if (hasCameraPermission === false) {
return <Text> No access to camera </Text>;
}
return (
<View
style={{
flex: 1,
flexDirection: 'column',
justifyContent: 'flex-end',
}}> ...
</View>
);
}
handleBarCodeScanned = ({ type, data}) => {
this.setState({
scanned: true,
});
alert(`Bar code with type ${type} and data ${data} has been scanned!`);
navigation.navigate('Menu')
};
};
So when I do scan something, it should navigate to the 'Menu' screen but instead I get the error: 'can't find variable: navigation'. How do I pass the navigation variable to a different js file?
i have seen your cod and got a solution for you you just have to create a new file NavigationServices.js
import { NavigationActions } from "react-navigation";
let _navigator;
function setTopLevelNavigator(navigatorRef) {
_navigator = navigatorRef;
}
function navigate(routeName, params) {
_navigator.dispatch(
NavigationActions.navigate({
routeName,
params
})
);
}
// add other navigation functions that you need and export them
export default {
navigate,
setTopLevelNavigator
};
and then import the file in your .js file and use it to navigate like in your OrderScreen.js:
import NavigationService from "../NavigationService";
and use it like this.
NavigationService.navigate("Qrcodescanner");

Problem with passing Params between Stack and Drawer Navigator screens - React-Native

Hi I am new to react native and trying to learn few things. I am trying to pass a data from one screen to another.
I need to pass the video id to Web View on another page to play YouTube video. but the Video Id is not passed to another screen.
I've tried to pass Param to one screen to another.In this project, I am using stack and drawer navigators.
The param id is "ytId"
also i tried to pass the param with AsyncStorage. Please anyone assist me with this issue and thanks in advance.
Screen 3:
import React from 'react';
import { Text, View, FlatList, Image, TouchableWithoutFeedback} from 'react-native';
import { Button, Icon } from 'native-base';
export default class App extends React.Component {
navOptions
static navigationOptions = ({ navigation }) => {
navOptions = navigation;
const { params = {} } = navigation.state;
return {
headerLeft: (
<Button
transparent
onPress={() => params._onHeaderEventControl()}
>
<Icon
name="menu"
style={{ fontSize: 30, color: 'white' }}
/>
</Button>
)
}
}
constructor(props) {
super(props);
this.state = { listLoaded: false };
}
onHeaderEventControl() {
const { params = {} } = navOptions.state;
params._openNav()
}
componentDidMount() {
this.props.navigation.setParams({
_onHeaderEventControl: this.onHeaderEventControl,
_openNav: () => this.openDrawer()
})
return fetch(
'https://www.googleapis.com/youtube/v3/search?part=snippet&q=lcwell&type=video&key=AIzaSyCwCHIfFvkMZ1aR6eIvy4sUIgqV6hIZ3qU')
.then((response) => response.json())
.then((responseJson) => {
this.setState({
listLoaded: true,
videoList: Array.from(responseJson.items)
})
})
.catch((error) => {
console.error(error);
});
}
openDrawer() {
this.props.navigation.openDrawer();
}
render() {
const { navigate } = this.props.navigation;
return (
<View>
{this.state.listLoaded && (
<View style={{ paddingTop: 0 }}>
<FlatList
data={this.state.videoList}
renderItem={({ item }) =>
<TubeItem
navigate={navigate}
id={item.id.videoId}
title={item.snippet.title}
imageSrc={item.snippet.thumbnails.high.url}
/>
}
keyExtractor={(item, index) => index.toString()}
/>
</View>
)}
{!this.state.listLoaded && (
<View style={{ paddingTop: 30 }}>
<Text>LOADING</Text>
</View>
)}
</View>
);
}
}
export class TubeItem extends React.Component {
onPress = () => {
this.props.navigate('Screen5', { ytId: this.props.id })
};
render() {
return (
<TouchableWithoutFeedback onPress={this.onPress}>
<View style={{ paddingTop: 20, alignItems: 'center' }}>
<Image
style={{ width: '100%', height: 200 }}
source={{ uri: this.props.imageSrc }}
/>
<Text>
{this.props.title}
</Text>
</View>
</TouchableWithoutFeedback>
);
}
}
Screen 5:
import React from 'react';
import { WebView } from 'react-native';
export default class VideoDetail extends React.Component {
navOptions
static navigationOptions = ({ navigation }) => {
navOptions = navigation;
const { params = {} } = navigation.state;
}
onHeaderEventControl() {
const { params = {} } = navOptions.state;
params._openNav()
}
componentDidMount() {
this.props.navigation.setParams({
_onHeaderEventControl: this.onHeaderEventControl,
_openNav: () => this.openDrawer()
})
}
render() {
let tubeId = this.props.navigation.getParam('ytId', 'NO VIDEO');
let tubeUrl = `https://www.youtube.com/embed/${tubeId}`;
return (
<WebView
style={{ marginTop: 20 }}
javaScriptEnabled={true}
source={{ uri: tubeUrl }}
/>
);
}
}
I would suggest you to use a state container like redux.
It allows you to pass variable and parameters from a component to another.
I didn't explain all in details, others do it better than me and there a re a lot of tutorials to implement redux.
You can find the official redux website https://redux.js.org/introduction/getting-started
Main steps would be:
Import redux in your package.json
Create a store with createStore method from imported package
Surround your main view with new created object <Provider store={store}>
Declare needed methods in your store
Connect Screen 3 & Screen 5 to redux
You will then be able to pass variable between your screens and access it very easy via props property.
It will simplify your life!
Otherwise we would need the way you declare your Stack and Drawer to be able to answer :-)

using react-navigation shows not a react component

I am trying to navigate between the screens. I installed npm react-navigation for this purpose. I am trying to go back from my AutoCompActivity page to app.js page. I have the following code on my AutoCompActivity page:
import HomeActivity from '../App'
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=[];
}
OpenHomePageFunction = () =>
{
this.props.navigation.navigate('Home');
}
and finally, I have this in my code:
export default MyNewProject= StackNavigator(
{
Home: {screen:HomeActivity}
}
I am getting the below error:
My AutoCompActivity.js resides inside a folder called Module, module reside inside the root folder' and app.js resides into the root folder of application.
Below is my App.js code:
import React, { Component } from 'react';
import { AppRegistry, StyleSheet, Text, View, Button, Image, TouchableOpacity,Platform } from 'react-native';
import { StackNavigator } from 'react-navigation';
import MissionActivity from './Modules/MissionActivity' ;
import AutoCompActivity from './Modules/AutoCompActivity' ;
import SearchServices from './Modules/SearchServices';
class MainActivity extends Component {
constructor(){
super();
this.state={
isVisible : true,
}
}
Hide_Splash_Screen=()=>{
this.setState({
isVisible : false
});
}
componentDidMount(){
var that = this;
setTimeout(function(){
that.Hide_Splash_Screen();
}, 5000);
}
static navigationOptions = {
title: '',
};
OpenSecondActivityFunction = () =>
{
this.props.navigation.navigate('Mission');
}
OpenThirdActivityFunction = () =>
{
this.props.navigation.navigate('autoComp');
}
OpenSearchSer = () =>
{
this.props.navigation.navigate('SearchSer');
}
render()
{
let Splash_Screen = (
<View style={styles.SplashScreen_RootView}>
<View style={styles.SplashScreen_ChildView}>
{/* Put all your components Image and Text here inside Child view which you want to show in Splash Screen. */}
<Image source={require('./Resources/CAC.png')}
style={{width:'100%', height: '100%', resizeMode: 'contain'}} />
</View>
<TouchableOpacity
activeOpacity = { 0.5 }
style={styles.TouchableOpacity_Style}
onPress={this.Hide_Splash_Screen} >
<Image source={{uri: 'https://reactnativecode.com/wp-content/uploads/2018/01/close_button.png'}}
style={{width:25, height: 25}} />
</TouchableOpacity>
</View> )
return(
<View style = { styles.MainContainer }>
<View style={styles.toolbar}>
<Image
resizeMode='contain'
style={styles.toolbarTitle}
source={require('./Resources/LogoWithDesc.jpg')} />
</View>
<View>
<Image
style={styles.title}
source={require('./Resources/Pot.png')} />
</View>
<View style={styles.searchButton}>
<Button onPress = { this.OpenSecondActivityFunction } title = 'Mission'/>
</View>
<View style={styles.searchButton}>
<Button onPress = { this.OpenThirdActivityFunction } title = 'Available Services'/>
</View>
{
(this.state.isVisible === true) ? Splash_Screen : null
}
</View>
);
}
}
export default ActivityProject = StackNavigator(
{
First: { screen: MainActivity, navigationOptions:{header:null} },
Mission: { screen: MissionActivity },
SearchSer: { screen: SearchServices },
autoComp:{screen: }
});

How to make a like function similar to Instagram (like button) with react native

Hello I am trying to make a Instagram like button with react-native by changing the image on press, but when I press the image no changes
Everything is up to date. And the code has no errors.
Here is my code:
import React, { Component } from 'react';
import { View, Text, StyleSheet, Image,navigation,TouchableOpacity } from 'react-native';
import { Container, Content, Badge, Left, Icon, Header} from 'native-base';
import { DrawerActions } from 'react-navigation';
class HomePage extends Component {
constructor(props){
super(props)
this.state = {
likedQ: false,
uri: require('./images/mianIcons/like.png')
}
}
_ifLiked = () => {
likedQ = true;
uri: require('./images/mianIcons/like3.png')
}
render(){
return(
<View>
<Header>
<Left>
<Icon name="ios-menu" onPress={()=> this.props.navigation.openDrawer()}
/>
</Left>
</Header>
<TouchableOpacity onPress={this._ifLiked()}>
<Image
style={{width: 32 , height: 32 ,}}
source={require(uri)}
/>
</TouchableOpacity>
</View>
)
}
}
export default HomePage;
You should set state to rerender the component
_ifLiked = () => {
this.setState({
likedQ: true,
uri: require('./images/mianIcons/like3.png')
})
}
change your onPress function like this. It is basic thing that you should set state for react components to update
There are some more corrections. Following is the corrected code
class HomePage extends Component{
constructor(props){
super(props)
this.state = {
likedQ: false,
uri: './images/mianIcons/like.png'
}
}
_ifLiked = () => {
this.setState({
likedQ: true,
uri: require('./images/mianIcons/like3.png')
}
}
render(){
return(
<View>
<Header>
<Left>
<Icon name="ios-menu" onPress={()=> this.props.navigation.openDrawer()} />
</Left>
</Header>
<TouchableOpacity onPress={() => this._ifLiked}>
<Image style={{width: 32 , height: 32}} source={require(this.state.uri)} />
</TouchableOpacity>
</View>
)}
}

Strange header height

For some strange reason, the header has a height of 667. I have copy pasted the code from an example page. See screenshot:
Code:
import React, { Component } from 'react';
import { Container, Header, Left, Body, Right, Button, Icon, Title } from 'native-base';
export default class HeaderIconTextExample extends Component {
render() {
return (
<Container>
<Header style={{backgroundColor:'red'}}>
<Left>
<Button transparent>
<Icon style={{color:'white'}} name='menu' />
</Button>
</Left>
<Body>
<Title style={{color:'white'}}>{this.props.headerText}</Title>
</Body>
<Right>
<Button transparent>
<Icon style={{color:'white'}} name='ios-add' />
</Button>
</Right>
</Header>
</Container>
);
}
}
I have tried to apply a height to the container (e.g. 100 pixels) but that does not change anything.
Update
I have realised, that if I remove ScrollView, then the content is in the very top, in front of the header, like this:
Code:
import React, {
Component
} from 'react';
import {
ScrollView, View
} from 'react-native';
import KeyDetail from './KeyDetail'
import axios from 'axios';
class KeyList extends Component {
state = {
keys: []
};
componentWillMount() {
axios.get('https://rallycoding.herokuapp.com/api/music_albums')
.then(response => this.setState({ keys: response.data }));
}
renderKeys() {
return this.state.keys.map(key =>
<KeyDetail thekey={key} key={key.title} />
);
}
render() {
return (
<ScrollView>
{ this.renderKeys() }
</ScrollView>
);
}
}
export default KeyList;
index.ios.js
/**
* Import a library to help create a component
*/
import React from 'react';
import {
AppRegistry,
View
} from 'react-native';
import Header from './src/components/Header';
import KeyList from './src/components/KeyList';
/**
* Create a component
*/
const App = () => (
<View style={{ flex: 1 }}>
<Header headerText={'Your Keys'} />
<KeyList />
</View>
);
/**
* Render to device
*/
AppRegistry.registerComponent('myapp', () => App);
Hmm. The solution (although not as pretty), is to wrap KeyList in index.ios.js inside a View, and then add marginBottom to prevent content from floating inside header.
index.ios.js
/**
* Import a library to help create a component
*/
import React from 'react';
import {
AppRegistry,
View
} from 'react-native';
import Header from './src/components/Header';
import KeyList from './src/components/KeyList';
/**
* Create a component
*/
const App = () => (
<View style={{ flex: 1 }}>
<Header headerText={'Your Keys'} />
<View>
<KeyList />
</View>
</View>
);
/**
* Render to device
*/
AppRegistry.registerComponent('uniqkey', () => App);
Header.js
import React, { Component } from 'react';
import { Container, Header, Left, Body, Right, Button, Icon, Title } from 'native-base';
export default class HeaderIconTextExample extends Component {
render() {
return (
<Container style={{marginBottom:64}}>
<Header style={{backgroundColor:'red'}}>
<Left>
<Button transparent>
<Icon style={{color:'white'}} name='menu' />
</Button>
</Left>
<Body>
<Title style={{color:'white'}}>{this.props.headerText}</Title>
</Body>
<Right>
<Button transparent>
<Icon style={{color:'white'}} name='ios-add' />
</Button>
</Right>
</Header>
</Container>
);
}
}
In your HeaderIconTextExample component you haven't specify the height for the header. Add this style in HeaderIconTextExample component.
const Styles = StyleSheet.create({
viewStyle: {
backgroundColor: '#F8F8F8',
justifyContent: 'center',
alignItems: 'center',
height: 60,
paddingTop: 15,
},
});
const { viewStyle } = Styles;
Update this line:
<Header style={{backgroundColor:'red'}}>
to this:
<Header style={viewStyle}>
It will work fine.
You can check my complete github repo code of this Albums react native App.

Resources