React Native Mathematical operation not working properly - reactjs

I am diving to this question from my previous question here: React Native mathematical actions not working
However, I got the problem from the answer there and updated my code (I know that I did not solve the illegal state modifying, the main system is not working properly).
App.js
import React, { Component } from 'react';
import {
ActivityIndicator,
Text,
View,
StyleSheet,
FlatList,
Alert,
TouchableOpacity,
ScrollView,
TextInput
} from 'react-native';
import {
Avatar,
Card,
Button,
Divider,
ListItem,
Image
} from 'react-native-elements';
import Icon from 'react-native-vector-icons/FontAwesome';
import HTML from 'react-native-render-html';
import UserAvatar from 'react-native-user-avatar';
import { StackNavigator } from 'react-navigation';
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import Cookies from 'universal-cookie';
import Heart from './components/heart';
const cookies = new Cookies();
class HomeScreen extends React.Component {
static navigationOptions = {
title: '',
};
constructor(props) {
super(props);
this.state = {
Loading: true,
data: [],
imageUrls: [],
isPress: false,
loveAction: '',
};
}
fetchLeash(user) {
return fetch('https://lishup.com/app/', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({ user }),
})
.then((response) => response.json())
.then((responseJson) => {
this.setState({ data: responseJson });
Promise.all(
responseJson.map(({ images }) => this.fetchImage(images))
).then((imageUrls) => this.setState({ imageUrls }));
})
.catch((error) => {
Alert.alert('error!');
})
.finally(() => {
this.setState({ Loading: false });
});
}
fetchImage(image) {
return fetch('https://lishup.com/app/fetch-image.php', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({ image }),
})
.then((response) => response.json())
.then((responseJson) =>
// Filter elements with empty string URLs, then app just the URL
responseJson.filter(({ url }) => url).map(({ url }) => url)
);
}
componentDidMount() {
this.fetchLeash(cookies.get('user'));
}
heartOnPress = (id, writer) => {
this.setState((state) => {
const data = state.data.map((el) => {
if(el.id === id) {
if(el.isLiked == true){
el.loves = el.loves - 1;
} else {
el.loves = el.loves + 1;
}
el.isliked = !el.isliked;
}
return el;
});
const isPress = !state.isPress
return { data, isPress };
});
fetch('https://lishup.com/app/love.php', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
id: id,
user: cookies.get('user'),
author: writer
}),
})
.then((response) => response.json())
.then((responseJson) => {
});
};
renderLeash = ({ item, index }) => (
<View>
<Card
style={{
height: 100,
justifyContent: 'center',
alignItems: 'center',
}}>
<ListItem
leftAvatar={{
title: item.user,
source: { uri: item.userpic },
}}
title={item.user}
subtitle={item.time}
chevron
/>
<Divider style={{ margin: 5, backgroundColor: 'white' }} />
<HTML html={item.text} />
<ScrollView
horizontal={true}
>
<View style={{flex:1, flexDirection:'row'}}>
{this.state.imageUrls[index] && this.state.imageUrls[index].length
? this.state.imageUrls[index].map((uri) => (
<Image
source={{ uri }}
style={{ flex:1, width: 500, height: 500, resizeMode: 'contain'}}
PlaceholderContent={<ActivityIndicator />}
/>
))
: null}
</View>
</ScrollView>
<Text>{item.loves}</Text>
<Text>{this.state.loveAction}</Text>
<Heart isLiked={item.isliked} main={item.user} id={item.id} onPress={this.heartOnPress} />
</Card>
</View>
);
render() {
if (this.state.Loading == true) {
cookies.set('user', 'LishUp', { path: '/' });
return (
<ActivityIndicator
size="large"
style={{ marginTop: 100 }}
color="#0000ff"
/>
);
} else {
return (
<View>
<FlatList
style={{ width: 400 }}
data={this.state.data}
keyExtractor={(item, idx) => idx}
renderItem={this.renderLeash}
/>
</View>
);
}
}
}
const styles = StyleSheet.create({});
const RootStack = createStackNavigator(
{
Home: { screen: HomeScreen },
},
{
initialRouteName: 'Home',
}
);
export default createAppContainer(RootStack);
heart.js
import React from 'react';
import { View, TouchableOpacity } from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome';
const Heart = ({ isLiked, onPress, main, id }) => {
return (
<View>
{isLiked ? (
<TouchableOpacity onPress={() => onPress(id, main)}>
<Icon name="heart" size={30} color="red" />
</TouchableOpacity>
) : (
<TouchableOpacity onPress={() => onPress(id, main)}>
<Icon name="heart" size={30} color="grey" />
</TouchableOpacity>
)}
</View>
);
};
export default Heart;
The problem right is: Suppose, there is 2 loves in a post. I pressed love. It just adds 1 beside the number 2 instead of doing an addition. Like- it becomes 21 instead of being 3
I can't understand where is the mistake, does react native avoid this kind of mathematical operation?
My snack: https://snack.expo.io/#nothingtosay/privileged-toffee

First of call you can change you Heart component
import React from 'react';
import { View, TouchableOpacity } from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome';
const Heart = ({ isLiked, onPress, main, id }) => {
return (
<View>
<TouchableOpacity onPress={() => onPress(id, main)}>
<Icon name="heart" size={30} color={isLiked?"red":"grey"} />
</TouchableOpacity>
</View>
);
};
export default Heart;
and you can parse the el.loves value before adding and subtracting Like this
el.loves = parseInt(el.loves) - 1;
el.loves = parseInt(el.loves) + 1;

It is just treating your “loves” as a string. Convert to number first with parseInt:
if(el.isLiked == true){
el.loves = parseInt(el.loves) - 1;
} else {
el.loves = parseInt(el.loves) + 1;
}

Related

React native, axios put request

The first problem: when opening a modal with editing an avatar, 2 requests are sent to the server.
The second problem: the avatar is not updated. The answer comes that the email should be specified, but I just pass the string. The full text of the error is shown in the screenshot.
Sending an avatar change request
import { BottomSheet } from '#rneui/themed'
import { FC, useState } from 'react'
import { useForm } from 'react-hook-form'
import { Pressable, ScrollView, View } from 'react-native'
import GestureRecognizer from 'react-native-swipe-gestures'
import { IUser } from '#/types/user.inteerface'
import { IAvatarEdit } from '#/components/screens/profile/avatarEdit/avatarEdit.interface'
import { useAvatar } from '#/components/screens/profile/avatarEdit/useAvatar'
import { Avatars, Button, Heading, Layout } from '#/components/ui'
import { getModalStyle, modalStyle } from '#/components/ui/style'
type AvatarData = {
image_url: string
}
const dataList: AvatarData[] = [
{
image_url:
'https://cdn.pixabay.com/photo/2017/03/01/22/18/avatar-2109804_1280.png'
},
{
image_url: 'https://randomuser.me/api/portraits/men/36.jpg'
},
{
image_url:
'https://cdn.pixabay.com/photo/2019/11/03/20/11/portrait-4599553__340.jpg'
},
{
image_url:
'https://cdn.pixabay.com/photo/2014/09/17/20/03/profile-449912__340.jpg'
},
{
image_url:
'https://cdn.pixabay.com/photo/2020/09/18/05/58/lights-5580916__340.jpg'
},
{
image_url:
'https://cdn.pixabay.com/photo/2016/11/21/12/42/beard-1845166_1280.jpg'
},
{
image_url:
'https://cdn.pixabay.com/photo/2012/04/18/18/07/user-37448_1280.png'
},
{
image_url: 'https://randomuser.me/api/portraits/men/36.jpg'
},
{
image_url:
'https://cdn.pixabay.com/photo/2019/11/03/20/11/portrait-4599553__340.jpg'
},
{
image_url:
'https://cdn.pixabay.com/photo/2014/09/17/20/03/profile-449912__340.jpg'
},
{
image_url:
'https://cdn.pixabay.com/photo/2020/09/18/05/58/lights-5580916__340.jpg'
},
{
image_url:
'https://cdn.pixabay.com/photo/2016/11/21/12/42/beard-1845166_1280.jpg'
}
]
const AvatarEdit: FC<IAvatarEdit> = ({ onClose, isVisible, ...props }) => {
const { setValue } = useForm<IUser>()
const { onSubmit, user } = useAvatar(setValue)
const [selected, setSelected] = useState<string>(user?.avatar || '')
const onAvatarSubmit = () => {
onSubmit({ avatar: selected } as IUser)
onClose()
}
return (
<GestureRecognizer
onSwipeDown={onClose}
config={{
velocityThreshold: 0.3,
directionalOffsetThreshold: 80
}}
style={{
flex: 1
}}
>
<BottomSheet
backdropStyle={{
backgroundColor: 'rgba(0, 0, 0, 0.5)'
}}
onBackdropPress={onClose}
isVisible={isVisible}
{...props}
>
<Layout
style={{
...getModalStyle(modalStyle)
}}
>
<View
style={{
flex: 1,
paddingHorizontal: 20,
paddingVertical: 20
}}
>
<Heading className='pb-3' title='Edit' />
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'flex-start'
}}
>
<Avatars
rounded={true}
size={100}
source={selected ? { uri: selected } : { uri: user?.avatar }}
/>
<View
style={{
marginTop: 15,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'flex-end'
}}
>
<Button style={{ marginRight: 10 }} onPress={onAvatarSubmit}>
Save
</Button>
</View>
</View>
</View>
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
style={{ flex: 1 }}
>
{dataList.map((item, index) => (
<Pressable key={index}>
<Avatars
onPress={() => setSelected(item.image_url)}
rounded={true}
key={index}
size={60}
source={{ uri: item.image_url }}
/>
</Pressable>
))}
</ScrollView>
</Layout>
</BottomSheet>
</GestureRecognizer>
)
}
export default AvatarEdit
import { IAuthFormData } from '#/types/auth.interface'
import { IUser } from '#/types/user.inteerface'
import { getUserUrl } from '#/config/api.config'
import { request } from '#/services/api/request.api'
export const UserService = {
async getAll(searchTerm?: string) {
return request<IUser[]>({
url: getUserUrl(''),
method: 'GET',
params: searchTerm ? { searchTerm } : {}
})
},
async getProfile() {
return request<IUser>({
url: getUserUrl('profile'),
method: 'GET'
})
},
async getById(_id: string) {
return request<IUser>({
url: getUserUrl(`${_id}`),
method: 'GET'
})
},
async updateProfile(data: IAuthFormData) {
return request<IUser>({
url: getUserUrl('profile'),
method: 'PUT',
data
})
},
async updateUser(data: IAuthFormData, _id: string) {
return request<string>({
url: getUserUrl('profile'),
method: 'PUT',
data
})
},
async updateAvatar(data: IUser) {
return request<string>({
url: getUserUrl('profile'),
method: 'PUT',
data
})
},
async deleteUser(_id: string) {
return request<string>({
url: getUserUrl(`${_id}`),
method: 'DELETE'
})
}
// async getFavorites() {
// return request<IUser>({
// url: getUserUrl('profile/favorites'),
// method: 'GET'
// })
// },
}
import { useMutation, useQuery } from '#tanstack/react-query'
import { SubmitHandler, UseFormSetValue } from 'react-hook-form'
import Toast from 'react-native-toast-message'
import { IUser } from '#/types/user.inteerface'
import { UserService } from '#/services/user/user.service'
export const useAvatar = (setValue: UseFormSetValue<IUser>) => {
const { isLoading, data: user } = useQuery(
['avatar'],
() => UserService.getProfile(),
{
onSuccess: ({ avatar }) => {
setValue('avatar', avatar)
}
}
)
const { mutateAsync } = useMutation(
['update avatar'],
(data: IUser) => UserService.updateAvatar(data),
{
onSuccess: ({}) => {
Toast.show({
type: 'success',
text1: 'avatar update',
text2: 'avatar update was successful'
})
}
}
)
const onSubmit: SubmitHandler<IUser> = async data => {
await mutateAsync(data)
}
return { onSubmit, isLoading, user }
}

JSON.stringify cannot serialize cyclic structure when passing state

I have problem when fetching data in react-native. I'm trying to send parts of my state in body of POST. I dont understand where is cyclic structure in my code. I dont see any cyclic structures.
I know the error is caused by state because when i simply put some strings in body everything is going alright.
import React from 'react';
import {Text, View, Button, StyleSheet, TextInput, TouchableOpacity} from "react-native";
export default class AddKidScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
name: '',
age: '',
parentID: props.navigation.getParam('myID', 0)
}
}
handleAddKid() {
let url = "https://piotr2.scementowani.pl/apiPiotr";
let name = this.state.name;
let age = this.state.age;
fetch(url, {
method: 'POST',
headers: {
'Content-Type': "application/json",
},
body: JSON.stringify({
method: "addKid",
name: name,
age: age,
}),
})
.then(response => response.json())
.then(responseJson => {
this.props.navigation.navigate('Main');
})
.catch((error) => {
console.error(error);
});
}
updateValue(text,field) {
if (field == 'name') {
this.setState({
name: text,
})
} else if (field == 'age' ){
this.setState( {
age: text,
})
}
}
render() {
return(
<View>
<View style={{flexDirection: 'row', width: '100%'}}>
<Text>
Imię:
</Text>
<TextInput
placeholder = "Imię"
onChange = {(text) => this.updateValue(text,'name')}
/>
</View>
<View style={{flexDirection: 'row', width: '100%'}}>
<Text>
Wiek:
</Text>
<TextInput
placeholder = "Wiek"
onChange = {(text) => this.updateValue(text,'age')}
/>
</View>
<TouchableOpacity onPress={this.handleAddKid.bind(this)}>
<Text>DODAJ</Text>
</TouchableOpacity>
</View>
)
}
}
When running handleAddKid()
I get JSON.stringify cannot serialize cyclic structure.

Mapping over data after fetching nested objects

Hello guys so i have component homescreen which i am fetching data inside and, the data i am getting contains some objects that has arrays inside, so i want to push all that arrays and data inside my state otherDetails key .
the data i am getting looks like this
{
id: 5,
url: "http://www.tvmaze.com/shows/5/true-detective",
name: "True Detective",
type: "Scripted",
language: "English",
genres: [
"Drama",
"Crime",
"Thriller"
],
status: "To Be Determined",
runtime: 60,
premiered: "2014-01-12",
officialSite: "http://www.hbo.com/true-detective",
schedule: {
time: "21:00",
days: [
"Sunday"
]
},
rating: {
average: 8.2
},
weight: 97,
network: {
id: 8,
name: "HBO",
country: {
name: "United States",
code: "US",
timezone: "America/New_York"
}
},
webChannel: null,
externals: {
tvrage: 31369,
thetvdb: 270633,
imdb: "tt2356777"
},
image: {
medium: "http://static.tvmaze.com/uploads/images/medium_portrait/178/445621.jpg",
original: "http://static.tvmaze.com/uploads/images/original_untouched/178/445621.jpg"
},
summary: "<p>Touch darkness and darkness touches you back. <b>True Detective</b> centers on troubled cops and the investigations that drive them to the edge. Each season features a new cast and a new case.</p>",
now what i am trying to do inside home screen i have my state with the object key otherDetails which i am trying to get genres language network schedule and summary so i am not sure what is happening wrong
this is my HomeScreen.js
import React, {Component} from 'react';
const axios = require('axios');
import Card from '../Components/Card/card';
import {
View,
Text,
Button,
Image,
ScrollView,
ActivityIndicator,
} from 'react-native';
import DetailsScreen from './detailsScreen';
import DetailedCard from '../Components/DetailedCard/DetailedCard';
export default class HomeScreen extends React.Component {
state = {
title: [],
image: [],
rating: [],
otherDetails:[{
genres:[],
schedule:[],
language:'',
network:[],
summary:'',
} ],
isLoading: true,
};
componentDidMount() {
this.getData();
}
getData = () => {
const requestUrls = Array.from({length: 9}).map(
(_, idx) => `http://api.tvmaze.com/shows/${idx + 1}`,
);
const handleResponse = data => {
const shows = data.map(show => show.data);
this.setState({
isLoading: false,
title: shows.map(show => show.name),
image: shows.map(show => show.image.medium),
rating: shows.map(show => show.rating.average),
otherDetails:shows.map((show,index)=>{
return [
show.genres[index],
show.schedule[index],
show.language[index],
show.network[index],
show.summary[index],
];
}),
});
};
const handleError = error => {
this.setState({
isLoading: false,
});
};
console.log(this.state.otherDetails.genres);
Promise.all(requestUrls.map(url => axios.get(url)))
.then(handleResponse)
.catch(handleError);
};
render() {
const {isLoading, title, image, rating, otherDetails} = this.state;
if (isLoading) {
return <ActivityIndicator size="large" color="#0000ff" />;
}console.log(this.state);
return (
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<View style={{backGroundColor: 'red'}} />
<ScrollView style={{flex: 1}}>
<Card
title={this.state.title}
rating={this.state.rating}
source={this.state.image}
navigation = {this.props.navigation}
/>
</ScrollView>
<Text>here images</Text>
</View>
);
}
}
any help would be nice thank you in advanced ...!
Storing the response from tvmaze as an array instead of trying to map all the values to keys would make your life a bit easier.. Something like this should work:
import axios from 'axios'
import React from 'react'
import { ActivityIndicator, ScrollView, Text, View } from 'react-native'
import Card from '../Components/Card/card'
export default class HomeScreen extends React.Component {
state = {
shows: [],
isLoading: true
}
componentDidMount () {
this.getData()
}
getData = () => {
const requestUrls = Array.from({length: 9}).map(
(_, idx) => `http://api.tvmaze.com/shows/${idx + 1}`
)
const handleResponse = data => {
console.log(data)
this.setState({
isLoading: false,
shows: data
})
}
const handleError = error => {
console.log(error)
this.setState({
isLoading: false
})
}
Promise.all(requestUrls.map(url => axios.get(url)))
.then(handleResponse)
.catch(handleError)
}
render () {
const {isLoading, shows} = this.state
if (isLoading) {
return <ActivityIndicator size='large' color='#0000ff' />
}
console.log(this.state)
return (
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<View style={{backGroundColor: 'red'}} />
<ScrollView style={{flex: 1}}>
{shows.length && shows.map(show => (
<Card key={show.data.id}
title={show.data.name}
{/*navigation={this.props.navigation}*/}
/>
))}
</ScrollView>
<Text>here images</Text>
</View>
)
}
}

Understanding React Natives setState and componentWillMount from FlatList

So I'm trying to make a simple application with expo and expo audio that will generate a list of audio buttons and text. But I cannot figure out how react works regarding redrawing the setState OUTSIDE componentWillMount and how to remake a soundobject with a new URI
So right now it will work but only playing the FIRST uri, I assume this is because the object still exists.
And it will not change the state of the button, I know this is because react cant see its changing for some reason from FlatList
It works outside of it, if I only make one button in renders view.
FlatList will render the setStates if I use LegacyImplementation=true .. But Im warned this is deprecated. And it renders it for all buttons at the same time
This is my handlerClass:
export class TSSGetter extends React.Component {
constructor(props){
super(props);
this.state ={
isLoading: true,
playingStatus: "Play"
}
}
retrieveData() {
const endpoint = 'http://127.0.0.1:3333/get'
const data = {
"userId": "123412341234",
"hmac": "detteerikkeenrigtighmac"
}
return new Promise((resolve, reject) => {
fetch(endpoint, {
method: 'POST',
headers: {
'Accept': 'application/json',
'content-type':'application/json'
},
body: JSON.stringify(data)
})
.then((resp) => {
console.log('hej return')
return resp.json();
})
.then((resp) => {
resolve(resp);
console.log('resp')
}).catch(function(error) {
console.log(error,'naeh')
});
});
}
componentDidMount(){
this.retrieveData()
.then((resp) => {
var pages = resp.books.contentObjects
pages.map((userData) => {
console.log('superduper pages', userData.contentObjectId)
})
this.setState({
isLoading: false,
dataSource: resp.books.contentObjects,
dataroot: resp.books
});
}).catch((err) => {
//handle error
console.log("Api call error2");
alert(err);
})
}
async _playRecording(AudioURL) {
console.log(AudioURL)
const { sound } = await Audio.Sound.createAsync(
{uri: AudioURL},
{
shouldPlay: true,
isLooping: true,
},
this._updateScreenForSoundStatus,
);
this.sound = sound;
this.setState({
playingStatus: 'playing'
});
}
_updateScreenForSoundStatus = (status) => {
if (status.isPlaying && this.state.playingStatus !== "playing") {
this.setState({ playingStatus: "playing" });
} else if (!status.isPlaying && this.state.playingStatus === "playing") {
this.setState({ playingStatus: "donepause" });
}
};
async _pauseAndPlayRecording() {
if (this.sound != null) {
if (this.state.playingStatus == 'playing') {
console.log('pausing...');
await this.sound.pauseAsync();
console.log('paused!');
this.setState({
playingStatus: 'donepause',
});
} else {
console.log('playing...');
await this.sound.playAsync();
console.log('playing!');
this.setState({
playingStatus: 'playing',
});
}
}
}
_syncPauseAndPlayRecording() {
if (this.sound != null) {
if (this.state.playingStatus == 'playing') {
this.sound.pauseAsync();
} else {
this.sound.playAsync();
}
}
}
_playAndPause = (AudioURL) => {
console.log(AudioURL)
switch (this.state.playingStatus) {
case 'Play':
this._playRecording(AudioURL);
break;
case 'donepause':
case 'playing':
this._pauseAndPlayRecording();
break;
}
}
render(){
if(this.state.isLoading){
return(
<View style={{flex: 1, padding: 20}}>
<ActivityIndicator/>
</View>
)
}
const styling = {
flex: 1,
paddingTop:10
// flexDirection: 'row'
}
const data = this.state.dataroot;
return(
<View style={styles.container}>
<FlatList
data={this.state.dataSource}
renderItem={({item}) =>
<View>
<TouchableOpacity style={styles.button} onPress={() => this._playAndPause(item.AudioURL)}>
<Text style={styles.buttonText}>
{this.state.playingStatus}+ {item.contentObjectId}
</Text>
</TouchableOpacity>
<Text style={styles.description}>
{item.text},
</Text>
</View>
}
keyExtractor={(item, index) => item.contentObjectId}
/>
</View>
);
}
}
UPDATE: setting extraData={this.state} in flatlist updates the button.. But all the buttons. How do I change the scope of the button?
You could create a specific component for the items in the FlatList. Each of the items will then have their own state.
import React, { Component } from "react";
import { StyleSheet, Text, View } from "react-native";
import { FlatList } from "react-native-gesture-handler";
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<FlatList
keyExtractor={(item, index) => index.toString()}
data={[1, 2, 3, 4, 5]}
renderItem={({ item }) => <Sound />}
/>
</View>
);
}
}
class Sound extends Component {
constructor() {
super();
this.state = {
status: "IDLE"
};
}
onChangeState = value => {
this.setState({
status: value
});
};
render() {
const { status } = this.state;
return (
<View style={{width: 200,paddingVertical: 10}}>
<Text>Status: {status}</Text>
<View style={{ flex: 1,flexDirection: "row", justifyContent: "space-between" }}>
<Text onPress={() => this.onChangeState("PLAYING")}>PLAY</Text>
<Text onPress={() => this.onChangeState("STOPPED")}>STOP</Text>
<Text onPress={() => this.onChangeState("PAUSED")}>PAUSE</Text>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 100,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center"
}
});
I checked out in the docs, here, and I saw that it will re-render just if you pass the state prop, see this explanations:
By passing extraData={this.state} to FlatList we make sure FlatList itself will re-render when the state.selected changes. Without setting this prop, FlatList would not know it needs to re-render any items because it is also a PureComponent and the prop comparison will not show any changes.

Navigation from one page to another in react native using navigate

I am currently learning react native. I want to navigate from one screen to another using navigate() function. Navigate function is placed inside a fetch() function, so after i get the response from the server, I should be redirected to the next page. But currently i an having problem as the navigation code is not working if i put inside the fetch(). If i remove the code and place it outside the fetch then it is working.
Below is my written code (StepOne):
import React, { Component } from 'react';
import { Text, View, StyleSheet, ImageBackground, TextInput, TouchableOpacity, Alert } from 'react-native';
import { Tile } from 'react-native-elements';
export default class StepOne extends Component {
static navigationOptions = {
header: null
};
constructor(props) {
super(props);
this.state = {
userEmail : '',
userPhone : ''
}
}
moveToStepTwo = () => {
const {userEmail} = this.state;
const {userPhone} = this.state;
if(userEmail == '' || userPhone == '') {
Alert.alert('Warning' , 'Please Insert All the Required Details !!!!');
} else {
let url = 'registerProcessGetEmailValidity.jsp?';
let param_one = 'user_email='+userEmail;
let seperator_param = '&';
let full_url = '';
full_url = url + param_one;
let header = {
'Accept': 'application/json',
'Content-Type': 'application/json'
};
fetch( full_url, {
method: 'GET',
headers: header,
})
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(myJson);
if(myJson.message == 'No User') {
this.props.navigation.navigate('StepTwo', { userEmail: this.state.userEmail , userPhone: this.state.userPhone } );
} else if (myJson.message == 'Got User') {
Alert.alert('Warning' , 'Email is registered, Choose different email !!!!');
}
});
}
}
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.container}>
<ImageBackground source={require('../../img/background1.jpg')} style={styles.backgroundImage}>
<View style={styles.content}>
<Text style={styles.logo}> -- STEP 1 -- </Text>
<View style={styles.inputContainer}>
<TextInput
underlineColorAndroid='transparent' style={styles.input} placeholder='ENTER EMAIL'
onChangeText = {userEmail => this.setState({userEmail})} >
</TextInput>
<TextInput
underlineColorAndroid='transparent' keyboardType = {'numeric'} maxLength={12}
style={styles.input} placeholder='ENTER PHONE NUMBER' onChangeText = {userPhone => this.setState({userPhone})} >
</TextInput>
</View>
<View style={styles.buttonHolder}>
<TouchableOpacity style={styles.buttonContainer} onPress={ this.moveToStepTwo }>
<Text style={styles.buttonText}>NEXT</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.buttonContainer} onPress={ ()=> navigate('Home') } >
<Text style={styles.buttonText}>CANCEL</Text>
</TouchableOpacity>
</View>
</View>
</ImageBackground>
</View>
);
}
}
When I navigate to the 'StepTwo' screen after the fetch call, there is no response. I can't navigate to the next screen. It is like the navigate call inside the fetch is not working. Can anyone help me to solve this problem ?
And one more thing. Is the any fault in my code ? Since i am new to react native, i have no idea what I am writing is correct or not. Maybe regarding the this. something element.
I give another example (App.js):
import React from 'react';
import { StyleSheet, Text, View, TouchableOpacity } from 'react-native';
import { StackNavigator } from 'react-navigation';
import Expo from 'expo';
import HomeScreen from './app/screens/HomeScreen';
import LoginScreen from './app/screens/LoginScreen';
import RegisterScreen from './app/screens/RegisterScreen';
const NavigationApp = StackNavigator({
Home: { screen: HomeScreen },
Login: { screen: LoginScreen },
Register: { screen: RegisterScreen },
});
export default class App extends React.Component {
render() {
return (
<NavigationApp />
);
}
}
Then Login file (Login.js)
import React, { Component } from 'react';
import { Text, View, StyleSheet, ImageBackground, TextInput, TouchableOpacity, Alert } from 'react-native';
import { FormLabel, FormInput } from 'react-native-elements'
export default class Login extends Component {
static navigationOptions = {
header: null
};
constructor(props) {
super(props);
this.state = {
userName : '',
userPass : ''
}
}
login = () => {
const {userName} = this.state;
const {userPass} = this.state;
if(userName == '' || userPass == '') {
Alert.alert('Warning' , 'Please Insert All the Required Details !!!!');
} else {
let url = 'loginProcessGetUserDetails.jsp?';
let param_one = 'user_name='+userName;
let param_two = 'user_pass='+userPass;
let param_three = 'user_group=JOMLOKA';
let seperator_param = '&';
let full_url = '';
full_url = url + param_one + seperator_param + param_two + seperator_param + param_three;
let header = {
'Accept': 'application/json',
'Content-Type': 'application/json'
};
fetch( full_url, {
method: 'GET',
headers: header,
})
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(myJson);
if(myJson.message == 'No User') {
Alert.alert('Warning' , 'No User !!!!');
} else if (myJson.message == 'Wrong Password') {
Alert.alert('Warning' , 'Wrong Password !!!!');
} else if (myJson.message == 'Login') {
//Alert.alert('Success' , 'Login !!!!');
const { navigate } = this.props.navigation;
navigate("Register",{ userEmail: this.state.userEmail , userPhone: this.state.userPhone });
}
});
}
}
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.container}>
<ImageBackground source={require('../img/background1.jpg')} style={styles.backgroundImage}>
<View style={styles.content}>
<Text style={styles.logo}> -- LOGIN DEMO -- </Text>
<View style={styles.inputContainer}>
<TextInput underlineColorAndroid='transparent' style={styles.input} placeholder='ENTER USERNAME' onChangeText = {userName => this.setState({userName})} >
</TextInput>
<TextInput underlineColorAndroid='transparent' secureTextEntry={true} style={styles.input} placeholder='ENTER PASSWORD' onChangeText = {userPass => this.setState({userPass})} >
</TextInput>
</View>
<View style={styles.buttonHolder}>
<TouchableOpacity onPress={this.login} style={styles.buttonContainer}>
<Text style={styles.buttonText}>LOGIN</Text>
</TouchableOpacity>
<TouchableOpacity onPress={ ()=> navigate('Home') } style={styles.buttonContainer}>
<Text style={styles.buttonText}>CANCEL</Text>
</TouchableOpacity>
</View>
</View>
</ImageBackground>
</View>
);
}
}
That is another example with the same problem.
Replace
onPress={ this.moveToStepTwo }
with
onPress={()=> this.moveToStepTwo() }
this.props.navigation.navigate('StepTwo', { userEmail: this.state.userEmail , userPhone: this.state.userPhone } );
Are you sure your this is correct?
If you don't use Arrow Function, you need to do this var _this = this, then _this.props.navigation.navigate('StepTwo', { userEmail: this.state.userEmail , userPhone: this.state.userPhone } );
You can use Arrow functiom in fetch:
fetch(url, options)
.then(response => {
// ...
})
.catch(error => {
// ...
})
I assume that you have installed react-navigation plugin.
Now import your files in the app.js
like below :
import login from './login';
import StepTwo from './StepTwo';
const Nav = StackNavigator({
login : {screen: login},
StepTwo : {screen: StepTwo},
});
export default class FApp extends Component {
render() {
return (
<Nav/>
);
}
}
And in your login file. (Considering your this file as a login file)
if(myJson.message == 'No User') {
const { navigate } = this.props.navigation;
navigate("StepTwo",{ userEmail: this.state.userEmail , userPhone: this.state.userPhone });
} else if (myJson.message == 'Got User') {
Alert.alert('Warning' , 'Email is registered, Choose different email !!!!');
}

Resources