I cannot use "this" on a function - javascript

I am new to React Native. I want to create a simple counter button. I could not use "this", it gives error ('this' implicitly has type 'any' because it does not have a type annotation.). You can see my TabTwoScreen.tsx TypeScript code below. I searched other questions but i could not find what to do. Why this is not working and how can I correct it. Waiting for helps. Thanks a lot.
import * as React from 'react';
import { StyleSheet, Button, Alert } from 'react-native';
import EditScreenInfo from '../components/EditScreenInfo';
import { Text, View } from '../components/Themed';
export default function TabTwoScreen() {
const state={
counter: 0,
}
const but1 = () => {
this.setState({counter : this.state.counter + 1});
};
return (
<View style={styles.container}>
<Text style={styles.title}>Counter:{state.counter}</Text>
<Button
title="Increment"
onPress={but1}
accessibilityLabel="increment"
color="blue"
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
title: {
fontSize: 20,
fontWeight: 'bold',
},
separator: {
marginVertical: 30,
height: 1,
width: '80%',
},
});
Error Message

App Output:
import React, { useState } from 'react';
import { StyleSheet, Button, Alert, Text, View } from 'react-native';
export default function TabTwoScreen() {
// ๐Ÿ‘‡ You are using functional components so use the useState hook.
const [counter, setCounter] = useState(0);
const but1 = () => {
// ๐Ÿ‘‡then you can increase the counter like below
setCounter(counter + 1);
};
return (
<View style={styles.container}>
<Text style={styles.title}>Counter:{counter}</Text>
<Button
title="Increment"
onPress={but1}
accessibilityLabel="increment"
color="blue"
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
title: {
fontSize: 20,
fontWeight: 'bold',
},
});
And if you want to use Class based component then here is the implementation:
import React, { useState, Component } from 'react';
import { StyleSheet, Button, Alert, Text, View } from 'react-native';
export default class TabTwoScreen extends Component {
constructor(props) {
super(props);
this.state = {
counter: 0,
};
}
but1 = () => {
this.setState({ counter: this.state.counter + 1 });
};
render() {
return (
<View style={styles.container}>
<Text style={styles.title}>Counter:{this.state.counter}</Text>
<Button
title="Increment"
onPress={this.but1}
accessibilityLabel="increment"
color="blue"
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
title: {
fontSize: 20,
fontWeight: 'bold',
},
});
Working App: Expo Snack

Please take a look at https://reactjs.org/docs/react-component.html#setstate
Remove this from your code and let only state.count + 1
An example I did in freedcodecamp.
handleChange(event){
//event.target.value
this.setState({
input: event.target.value
});
}
// Change code above this line
render() {
return (
<div>
{ /* Change code below this line */}
<input value={this.state.input} onChange={(e) => this.handleChange(e)}/>

That is because you are using a function component. You have to either use a class based component (React class and function components) or switch over to React hooks with the useState hook.
Here's the example with a class based component:
import * as React from 'react';
import { StyleSheet, Button, Alert } from 'react-native';
import EditScreenInfo from '../components/EditScreenInfo';
import { Text, View } from '../components/Themed';
export default class TabTwoScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
counter: 0
}
}
but1() {
this.setState({ counter: this.state.counter + 1 });
};
render() {
return (
<View style={styles.container}>
<Text style={styles.title}>Counter:{state.counter}</Text>
<Button
title="Increment"
onPress={this.but1}
accessibilityLabel="increment"
color="blue"
/>
</View>
);
}
}
And here's with React hooks:
import React, {useState} from 'react';
import { StyleSheet, Button, Alert } from 'react-native';
import EditScreenInfo from '../components/EditScreenInfo';
import { Text, View } from '../components/Themed';
export default function TabTwoScreen() {
const [counter, setCounter] = useState(0);
const but1 = () => {
setCounter(counter + 1);
};
return (
<View style={styles.container}>
<Text style={styles.title}>Counter:{counter}</Text>
<Button
title="Increment"
onPress={but1}
accessibilityLabel="increment"
color="blue"
/>
</View>
);
}

Related

How would I call a function from another component in react native?

How would I call a function from another component?
App.js
<Button onPress={movePopUpCard()}></Button>
<PopUpCard/>
PopUpCard.js
const movePopUpCard = () => {
//Code to update popUpCardX
}
<Animated.View style={[
{transform: [{scale: scale}, {translateX: popUpCardX}]},
{position: 'absolute'}
]}>
</Animated.View>
By using ref and forwardRef you can achieve this.
snack ex: https://snack.expo.io/#udayhunter/frisky-pretzels
App.js
import React,{useRef,useEffect} from 'react';
import { Text, View, StyleSheet } from 'react-native';
import PopUp from './PopUpCard'
const App =(props)=> {
const childRef = useRef(null)
return (
<View style={styles.container}>
<PopUp ref={childRef}/>
<Text
onPress = {()=>{
childRef.current.updateXvalue(10)
}}
>Press me</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
backgroundColor: '#ecf0f1',
padding: 8,
},
});
export default App
popUp.js
import React,{useState,useImperativeHandle,useEffect,forwardRef} from 'react'
import {View,Text,StyleSheet,Animated} from 'react-native'
const PopUp = (props,ref) => {
const [xValue, setXvalue] = useState(10)
const updateXvalue = (x)=>{
setXvalue(prev=> prev+x)
}
useImperativeHandle(ref, () => ({
updateXvalue
}));
return(
<Animated.View style = {[styles.mainView,{transform:[{translateX:xValue}]}]}>
</Animated.View>
)
}
const styles = StyleSheet.create({
mainView : {
height:100,
width:100,
backgroundColor:'red'
}
})
export default forwardRef(PopUp)
If you are using a functional component you have to use forwardRef to add reference to the component and useImperativeHandle to implement the method which you want to access through reference here is an example. Here I am calling bounce method which increases the scale of the component:
Snack: https://snack.expo.io/#ashwith00/adequate-salsa
Code:
App.js
export default function App() {
const boxRef = React.useRef();
return (
<View style={styles.container}>
<AnimatedBox ref={boxRef} />
<Button title="Bounce" onPress={() => boxRef.current.bounce()} />
</View>
);
}
AnimatedBox.js
import React, { forwardRef, useImperativeHandle, useRef } from 'react';
import { View, Animated } from 'react-native';
export default forwardRef((props, ref) => {
const scale = useRef(new Animated.Value(1)).current;
useImperativeHandle(
ref,
() => ({
bounce: () => {
Animated.timing(scale, {
toValue: 1.5,
duration: 300,
}).start(({ finished }) => {
if (finished) {
Animated.timing(scale, {
toValue: 1,
duration: 300,
}).start();
}
});
},
}),
[]
);
return (
<Animated.View
style={{
width: 100,
height: 100,
backgroundColor: 'red',
transform: [{scale}]
}}
/>
);
});
move the function movePopUpCard to app.js
and pass in app.js pass it in
<PopUpCard movePopUpCard={(params) => movePopUpCard(params)}/>
you can call the function from PopUpCard component by this.props.movePopUpCard(params)
you can also pass params if requrired

Unable to navigate to next screen in React Native

I have created a list of posts and want to pass details of one specfic post to another screen. I want to be able to click on the post and be directed to the post details screen. This is the PostList.js file:
import React, {Component} from 'react';
import {
FlatList,
StyleSheet,
View,
Text,
Modal,
TouchableOpacity,
} from 'react-native';
import Post from './Post';
import Firebase from 'firebase';
import 'firebase/database';
import {firebaseConfig} from './configFirebase';
import PostDetails from './stack/PostDetails';
export default class Posts extends Component {
constructor(props) {
super(props);
!Firebase.apps.length
? Firebase.initializeApp(firebaseConfig.firebase)
: Firebase.app();
this.state = {
postList: [],
navigation: this.props.navigation,
};
}
state = {
loading: false,
currentPost: null,
};
componentDidMount() {
this.getPostData();
}
getPostData = () => {
const ref = Firebase.database().ref('/posts');
ref.on('value', snapshot => {
console.log('DATA RETRIEVED');
const postsObject = snapshot.val();
if (!postsObject) {
return console.warn('No data from firebase');
}
const postsArray = Object.values(postsObject);
this.setState({postList: postsArray});
});
};
render() {
return (
<View style={styles.container}>
<FlatList
keyExtractor={post => post.heading}
data={this.state.postList}
renderItem={({item: post}) => (
<Post
key={post.heading}
heading={post.heading}
description={post.description}
location={post.location}
onPress={() => this.props.navigation.push('PostDetails', {post})}
/>
)}
/>
</View>
);
}
}
export const styles = StyleSheet.create({
container: {
borderWidth: 2,
borderRadius: 5,
backgroundColor: '#2bb76e',
flex: 1,
},
txtInput: {
flex: 1,
margin: 5,
padding: 5,
borderWidth: 2,
fontSize: 20,
borderRadius: 5,
backgroundColor: 'snow',
},
});
I've tried navigation.navigate() and navigation.push() and neither work.
This is the PostDetails Screen I want to navigate to and pass the post info to:
import React from 'react';
import {Text, View} from 'react-native';
export default ({route}) => {
const postInfo = route.params.post;
return (
<View>
<Text>{JSON.stringify(postInfo, null, 2)}</Text>
<Text>{postInfo.heading}</Text>
</View>
);
};
This is my HomeStack file where the screens are kept:
import React from 'react';
import {NavigationContainer} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
import Posts from '../PostList';
import AddForm from '../AddForm';
import PostDetails from './PostDetails';
const HomeStack = createStackNavigator();
const HomeStackScreen = () => (
<HomeStack.Navigator>
<HomeStack.Screen
name="PostList"
component={Posts}
options={{headerTitle: 'big APPetite'}}
/>
<HomeStack.Screen
name="PostDetails"
component={PostDetails}
options={({route}) => ({heading: route.params.post.heading})}
/>
<HomeStack.Screen name="NewPost" component={AddForm} />
</HomeStack.Navigator>
);
export default HomeStackScreen;
Post.js:
import React, {Component} from 'react';
import {
Image,
Text,
StyleSheet,
View,
TextInput,
FlatList,
TouchableOpacity,
} from 'react-native';
import FavouriteButton from './buttons/FavouriteButton';
import chickenClub from './images/chickenSandwich.jpg';
const Post = ({heading, description, location, username}) => (
<TouchableOpacity style={postStyle.container}>
<View style={(postStyle.container, {alignItems: 'flex-start'})}>
<View style={postStyle.padding}>
<Image style={postStyle.image} source={chickenClub} />
<View style={{backgroundColor: (255, 255, 255, 45), borderRadius: 6}}>
<Text style={postStyle.text}>{heading}</Text>
<Text style={postStyle.text}>{location}</Text>
<Text style={postStyle.text}>{username}*username*</Text>
</View>
</View>
<View
style={{
alignSelf: 'flex-end',
flexDirection: 'column',
backgroundColor: '#2bb76e',
}}>
<Text style={postStyle.paragraph}>{description}</Text>
<View style={{justifyContent: 'flex-start', alignItems: 'flex-end'}}>
<FavouriteButton />
</View>
</View>
</View>
</TouchableOpacity>
);
const postStyle = StyleSheet.create({
container: {
borderWidth: 2,
borderRadius: 5,
backgroundColor: '#2bb76e',
flex: 1,
},
padding: {
padding: 10,
},
heading: {
backgroundColor: (255, 250, 250, 50),
flexDirection: 'column',
},
paragraph: {
alignSelf: 'flex-end',
fontSize: 20,
},
username: {},
image: {
flexDirection: 'row',
height: 150,
width: 150,
},
text: {
fontSize: 25,
padding: 5,
},
});
export default Post;
You are passing onPress to your Post component, however you are not applying that prop to the TouchableOpacity.
Modifying the Post component to include:
const Post = ({heading, description, location, username, onPress}) => (
<TouchableOpacity style={postStyle.container} onPress={onPress}>

React Native changing background color according to data that comes through http request from server

I am new at React Native.
I'm working on a code that will change the background color of a box (card) according to the data that I will get from API. I want to check first if the title is like 'Taylor' make background red , if it is 'Fearless' make it green and so on.
Here is the API that I got information from :
http://rallycoding.herokuapp.com/api/music_albums
This is the code divided into several files.
First of them index.js
// Import a library to help to create a component
import React from 'react';
import { Text, AppRegistry, View } from 'react-native';
import Header from './src/components/header.js';
import AlbumList from './src/components/AlbumList.js'
// create a component
const App = () => (
<View>
<Header headerText={'Smart Parking'}/>
<AlbumList />
</View>
);
//render it to the device
AppRegistry.registerComponent('albums2', () => App);
second is AlbumList.js
import React, { Component } from 'react';
import { View } from 'react-native';
import axios from 'axios';
import AlbumDetail from './AlbumDetail.js'
class AlbumList extends Component {
state = { albums: [] };
componentWillMount() {
axios.get('https://rallycoding.herokuapp.com/api/music_albums')
.then(response => this.setState({ albums: response.data }) );
}
renderAlbums() {
return this.state.albums.map(album =>
<AlbumDetail key={album.title} album={album} />
);
}
render() {
return(
<View>
{this.renderAlbums()}
</View>
);
}
}
export default AlbumList;
3rd is AlbumDetail.js
import React from 'react';
import {Text, View} from 'react-native';
import Card from './Card.js'
const AlbumDetail = (props) => {
return(
<Card>
<Text> {props.album.title} </Text>
</Card>
);
};
export default AlbumDetail;
4th is card which I need to change background of it
import React from 'react';
import { View } from 'react-native';
const Card = (props) => {
return (
<View style={styles.containerStyle}>
{props.children}
</View>
);
};
const styles = {
containerStyle:{
borderWidth: 1,
borderRadius: 2,
backgroundColor: '#ddd',
borderBottomWidth: 0,
shadowColor: '#000',
shadowOffset: {width: 0, height:2 },
shadowOpacity: 0.1,
shadowRadius: 2,
elevation: 1,
marginLeft: 5,
marginRight: 5,
marginTop: 10
}
};
export default Card;
last one is header
// Import libraries for making components
import React from 'react';
import { Text, View } from 'react-native';
// make a components
const Header = (props) => {
const { textStyle, viewStyle } = styles;
return(
<View style={viewStyle}>
<Text style={textStyle}>{props.headerText}</Text>
</View>
)
};
const styles ={
viewStyle:{
backgroundColor:'orange',
justifyContent: 'center',
alignItems: 'center',
height: 60,
},
textStyle: {
fontSize: 20
}
};
// make the component to the other part of the app
export default Header;
Basically you need to pass the title of the album as prop to the Card from the AlbumDetails component and then on each Card calculate the color to use and pass it in the style like this:
// AlbumDetails.js component
import React from 'react';
import {Text, View} from 'react-native';
import Card from './Card.js'
const AlbumDetail = (props) => {
return(
<Card title={props.album.title}>
<Text> {props.album.title} </Text>
</Card>
);
};
export default AlbumDetail;
// Card.js component
import React from "react";
import { View } from "react-native";
function calculateColor(title) {
let bgColor;
switch (title) {
case "Taylor":
bgColor = "red";
break;
case "Fearless":
bgColor = "green";
break;
default:
bgColor = "orange";
break;
}
return bgColor;
}
const Card = props => {
const { title } = props;
const backgroundColor = calculateColor(title);
return (
<View style={[styles.containerStyle, { backgroundColor: backgroundColor }]}>
{props.children}
</View>
);
};
const styles = {
containerStyle: {
borderWidth: 1,
borderRadius: 2,
backgroundColor: "#ddd",
borderBottomWidth: 0,
shadowColor: "#000",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 2,
elevation: 1,
marginLeft: 5,
marginRight: 5,
marginTop: 10
}
};
export default Card;
Something like this should work:
Change the AlbumDetail to conditionally render the Card.
const AlbumDetail = props => {
if (props.album.title === 'Taylor') {
return (
<Card style={{ backgroundColor: 'red' }}>
<Text>{props.album.title}</Text>
</Card>
);
} else {
return (
<Card style={{ backgroundColor: 'green' }}>
<Text>{props.album.title}</Text>
</Card>
);
}
};
Override the default style of the card using the passed style prop.
const Card = props => {
return (
<View style={[styles.containerStyle, props.style]}>{props.children}</View>
);
};
accepted answer is great just its a bad habit to do things in render.
i also not sure since every title has a color why wouldnt the server send this in the object props in first place ? :)
class AlbumList extends Component {
state = { albums: [] };
componentDidMount() {
axios.get('https://rallycoding.herokuapp.com/api/music_albums')
.then(response=> Array.isArray(response.data) ? response.data : []) // alittle validation would not hurt :) !
.then(data => this.setState({ albums: data }) );
}
selectHeaderColorForAlbum( album ){
let headerColor = 'red';
// switch(album.title){ ..you logic }
return headerColor;
}
renderAlbums() {
return this.state.albums.map(album =>
<AlbumDetail key={album.title} album={album} color={this.selectHeaderColorForAlbum(album)} />
);
}
render() {
return(
<View>
{this.renderAlbums()}
</View>
);
}
}
const Card = (props) => {
return (
<View style={[styles.containerStyle,{color:props.headerColor}]}>
{props.children}
</View>
);
};
this is easier your logic will render only once.
also notice that react >16.0 depricated componentWillMount, so use DidMount

understanding "undefined is not an object('this.props.navigation.navigate)"

I am getting the error "undefined is not an object('this.props.navigation.navigate)" when I click the button titled with "Chat with Lucy" which is supposed to take me to the ChatScreen screen.
All of this code is within the App.js file i'm using that is being exported into the android and ios files.
Any reason why i'm getting this error? thanks!
import React, { Component } from 'react';
import { StackNavigator } from 'react-navigation';
import {
AppRegistry,
StyleSheet,
Text,
View,
Image,
TextInput,
Button
} from 'react-native';
export default class firstapp extends Component {
static navigationOptions = {
title: 'Welcome',
};
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.container}>
<Image source={require('./Packit_title.png')} />
<TextInput
style={styles.account}
/>
<TextInput
style={styles.account}
/>
<View style={styles.button}>
<Button
title="Login"
color="#c47735"
/>
<Button
title="Sign Up"
color="#c47735"
/>
</View>
<Button
onPress={() => navigate('Chat')}
title="Chat with Lucy"
/>
</View>
);
}
}
class ChatScreen extends Component {
static navigationOptions = {
title: 'Chat with Lucy',
};
render() {
return (
<View>
<Text>Chat with Lucy</Text>
</View>
);
}
}
const firstappNav = StackNavigator({
Home: { screen: firstapp },
Chat: { screen: ChatScreen },
});
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#f49542',
},
account: {
backgroundColor: '#ffffff',
height: 40,
borderColor: 'gray',
borderWidth: 1,
marginBottom: 10,
width: 200
},
button: {
flexDirection: 'row',
}
});
AppRegistry.registerComponent('firstapp', () => firstapp);
You are exporting your firstapp component which has no access to the navigation prop since nothing is being passed to it. You need to export your navigator component firstappNav instead.
AppRegistry.registerComponent('firstapp', () => firstappNav);
This is because props object is undefined in firstapp Component. You will have to override its constructor to access props. Read this

How to navigate page with React Native

I have a component for listing items, I want to add the function that can go to a different page, and that page has the detail about that item. Currently, this is my code for listing items.
import React, { Component } from 'react';
import { ScrollView } from 'react-native';
import axios from 'axios';
import CarDetail from './CarDetail';
const API_URL = 'http://localhost:3000';
class CarList extends Component {
state = { cars: [] };
componentWillMount() {
console.log('Mount');
axios.get(`${API_URL}/cars`)
.then(response => this.setState({ cars: response.data.cars }));
}
renderCars() {
return this.state.cars.map(car => <CarDetail key={car.id} car={car} />
);
}
render() {
console.log(this.state.cars);
return (
<ScrollView>
{this.renderCars()}
</ScrollView>
);
}
}
export default CarList;
and this is the code for describing items
import React from 'react';
import { Text, View, Image } from 'react-native';
import { Actions } from 'react-native-router-flux';
import Card from '../material/Card';
import CardSection from '../material/CardSection';
const CarDetail = ({ car }) => {
const imageURI = 'https://yt3.ggpht.com/-HwO-2lhD4Co/AAAAAAAAAAI/AAAAAAAAAAA/p9WjzQD2-hU/s900-c-k-no-mo-rj-c0xffffff/photo.jpg';
const { make, model } = car;
function showCarDetail() {
Actions.showCar();
}
return (
<Card>
<CardSection>
<View style={styles.containerStyle}>
<Image
style={styles.imageStyle}
source={{ uri: imageURI }}
/>
</View>
<View style={styles.headContentStyle}>
<Text
style={styles.headerTextStyle}
onPress={showCarDetail()}
>
{make}
</Text>
<Text>{model}</Text>
</View>
</CardSection>
<CardSection>
<Image
style={styles.picStyle}
source={require('./car.jpg')}
/>
</CardSection>
</Card>
);
};
const styles = {
headContentStyle: {
flexDirection: 'column',
justifyContent: 'space-around'
},
headerTextStyle: {
fontSize: 18
},
imageStyle: {
height: 50,
width: 50
},
containerStyle: {
justifyContent: 'center',
alignItems: 'center',
marginLeft: 10,
marginRight: 10
},
picStyle: {
height: 300,
flex: 1,
width: null
}
};
export default CarDetail;
How can I change my code for that? Can anyone give me an example?
You have to use some sort of navigation component. There are many out there, but personally I use the one that is built into React Native. https://facebook.github.io/react-native/docs/navigator.html

Categories

Resources