MapboxGL React Native UserLocation Indicator do not display on map - react-native

The UserIndicator from <MapboxGL.UserLocation>, work and display fine on IOS, but with android, it's depends, it sometime work, sometime not, and i realize also, that my CameraRef.current.setCamera() is undefined when the UserIndicator doesn't display.
I tried to request with all the way i could, the location permissions like this :
React Native :
PermissionsAndroid.requestMultiple(
[PermissionsAndroid.PERMISSIONS.ACCESS_COARSE_LOCATION],
{
title: 'Give Location Permission',
message: 'App needs location permission to find your position.'
}
).then((res) => console.log(res))
MapboxGL :
if (Platform.OS == "android") {
var temp = await MapboxGL.requestAndroidLocationPermissions()
}
expo :
let { status } = await Location.requestPermissionsAsync();
all this request permissions work fine and have a output "granted" or granted : true
this is my map Component :
var Map = ({ navigation }) => {
const MapRef = React.useRef(null)
const CameraRef = React.useRef(null)
const LocationRef = React.useRef(null)
const { user, setUser } = React.useContext(UserContext)
const [data, setDATA] = React.useState([null])
const [reload, setReload] = React.useState(false)
const {location, setLocation} = React.useContext(LocationContext)
console.log(location)
var test = null;
React.useEffect(() => {
MapboxGL.setTelemetryEnabled(false);
MapboxGL.locationManager.start();
return () => {
MapboxGL.locationManager.stop();
}
// console.log(LocationRef.current)
}, [])
function handleClick() {
CameraRef.current.setCamera({
centerCoordinate: [location.coords.longitude, location.coords.latitude],
zoomLevel: 11,
animationDuration: 200,
})
}
function CenterCamera() {
if (CameraRef.current) {
CameraRef.current.setCamera({
centerCoordinate: [location.coords.longitude, location.coords.latitude],
zoomLevel: 11,
animationDuration: 2000,
})
}
}
function goTo(latitude, longitude) {
CameraRef.current.setCamera({
centerCoordinate: [longitude, latitude],
zoomLevel: 13,
animationDuration: 100,
})
}
function DisplayPings(data) {
if (data.data.length > 0) {
if (data.data[0].type_id == null) {
data.data[0].type_id = 1;
}
const val = searchInJson(data.data[0].type_id)
const features = setFeatures(val, data.data[0])
return (
<View key={data.data[0].id_activity_data}>
<MapboxGL.Images
images={{
FootBall: json[0].url,
}}
/>
<MapboxGL.ShapeSource hitbox={{ width: 20, height: 20 }} onPress={() => goTo(data.data[0].latitude, data.data[0].longitude)} id={(data.data[0].id_activity_data).toString()} shape={features}>
<MapboxGL.SymbolLayer id={(data.data[0].id_activity_data).toString()} style={{ iconImage: ['get', 'icon'] }} />
</MapboxGL.ShapeSource>
</View>
);
}
}
if (location && location.city != null && data.data) {
return (
<View style={styles.page}>
<MapboxGL.MapView onPress={() => console.log("test")} ref={(ref) => {
}
} style={styles.map} compassEnabled={false} zoomEnabled={true} >
<MapboxGL.UserLocation />
<MapboxGL.Camera ref={(ref) => {
CameraRef.current = ref
CenterCamera()
}} />
{data.data.map((data) => DisplayPings(data))}
</MapboxGL.MapView>
<ComponentsOnmap></ComponentsOnmap>
<TouchableOpacity style={styles.rondLocation} onPress={handleClick}>
<FontAwesome5 name="location-arrow" size={24} color="#434040" />
</TouchableOpacity>
<BottomSheet city={location.city} data = {data} setReload = {setReload} navigation={navigation}></BottomSheet>
</View>)
}
else
return (
<View style={styles.page}>
<MapboxGL.MapView ref={MapRef} compassEnabled={false} style={styles.map} zoomEnabled={true} >
<MapboxGL.UserLocation ref={LocationRef} />
</MapboxGL.MapView>
<ComponentsOnmap></ComponentsOnmap>
<BottomSheet city="No location" navigation={navigation}></BottomSheet>
</View>
)
}
export default Map
My condition location && location.city != null works fine, i tried without it, but the problem is still the same
My Location Context :
import React, { Component, createContext, useState, useContext } from "react";
import { Platform, PermissionsAndroid } from "react-native"
import * as Location from 'expo-location';
import MapboxGL from "#react-native-mapbox-gl/maps";
import { GetLocation } from "../API/GetLocation"
export const LocationContext = createContext();
MapboxGL.setAccessToken("Je l'ai caché bande de petit malin");
export default LocationProvider = ({ children }) => {
const [location, setLocation] = useState({ coords: [], city: null, permission: false })
const [city, SetCity] = React.useState(null)
const [coords, setCoords] = React.useState([])
React.useEffect(() => {
PermissionsAndroid.requestMultiple(
[PermissionsAndroid.PERMISSIONS.ACCESS_COARSE_LOCATION],
{
title: 'Give Location Permission',
message: 'App needs location permission to find your position.'
}
).then((res) => console.log(res))
GetLocation.then((res) => {
setLocation(res)
})
}, [])
return (
<LocationContext.Provider value={{ location, setLocation, city, SetCity, coords, setCoords }}>
{children}
</LocationContext.Provider>
)
}
My GetLocation Promise
import { useContext } from "react"
import { Platform } from "react-native"
import * as Location from 'expo-location';
import MapboxGL from "#react-native-mapbox-gl/maps";
export const GetLocation = new Promise(async (resolve, reject) => {
if (Platform.OS == "android") {
var temp = await MapboxGL.requestAndroidLocationPermissions()
}
let { status } = await Location.requestPermissionsAsync();
if (status == "granted")
Location.getCurrentPositionAsync().then((location) => {
console.log(location)
console.log("ca marche ap")
let longitude = location.coords.longitude
let latitude = location.coords.latitude
return ({ latitude, longitude })
}).then(async (coords) => Location.reverseGeocodeAsync(coords).then(async (adress) => {
resolve({ coords: coords, city: adress[0].city, granted: true })
})).catch((error) => console.log(reject(error)));
})

Related

FlatList in ReactNative does not update/re-render when its data changes

Hej, I advanced my FlatList in React Native with
a) inbox/archive views
and b) with standard filter functionalities.
It's working somehow, but is not production ready!
Can someone please check this (I think well-organized) code and tell me where I do what wrong?
What is not working:
a) FlatList does not always re-render/update when the stream state, which is its data prop, changes
b) FlatList does not remove an item immediately when I archive/unarchive via swipe functionality. I have to manually change the view to see ...
c) FlatList does not directly apply the filter on state, I have to click twice to make it happen ...
//React
import { View, StyleSheet, Pressable, Animated, FlatList } from "react-native";
import { useCallback, useContext, useEffect, useState, useMemo } from "react";
//Internal
import SelectBtn from "./SelectBtn";
import SessionComponent from "./SessionComponent";
import LoadingOverlay from "../notification/LoadingOverlay";
import { SessionsContext } from "../../store/context-reducer/sessionsContext";
//External
import { Ionicons } from "#expo/vector-icons";
import { useNavigation } from "#react-navigation/native";
import { database, auth } from "../../firebase";
import { ref, onValue, remove, update } from "firebase/database";
function SessionStream() {
const navigation = useNavigation();
const sessionsCtx = useContext(SessionsContext);
const currentSessions = sessionsCtx.sessions;
const [isFetching, setIsFetching] = useState(true);
const [stream, setStream] = useState([]);
const [inbox, setInbox] = useState([]);
const [archive, setArchive] = useState([]);
const [filter, setFilter] = useState([]);
const sessionList = ["Sessions", "Archive"];
const sortList = ["ABC", "CBA", "Latest Date", "Earliest Date"];
useEffect(() => {
//Fetches all sessions from the database
async function getSessions() {
setIsFetching(true);
const uid = auth.currentUser.uid;
const sessionsRef = ref(database, "users/" + uid + "/sessions/");
try {
onValue(sessionsRef, async (snapshot) => {
const response = await snapshot.val();
if (response !== null) {
const responseObj = Object.entries(response);
const sessionsData = responseObj.map((item) => {
return {
id: item[1].id,
title: item[1].title,
laps: item[1].laps,
endTime: item[1].endTime,
note: item[1].note,
identifier: item[1].identifier,
date: item[1].date,
smed: item[1].smed,
externalRatio: item[1].externalRatio,
internalRatio: item[1].internalRatio,
untrackedRatio: item[1].untrackedRatio,
archived: item[1].archived,
};
});
sessionsCtx.setSession(sessionsData);
setIsFetching(false);
} else {
sessionsCtx.setSession([]);
setIsFetching(false);
}
});
} catch (err) {
alert(err.message);
setIsFetching(false);
}
}
getSessions();
}, []);
useEffect(() => {
//Sorts sessions into archived and unarchived
setInbox(
currentSessions.filter((session) => {
return session.archived === false || session.archived === undefined;
})
);
setArchive(
currentSessions.filter((session) => {
return session.archived === true;
})
);
}, [currentSessions, archiveHandler, unArchiveHandler, sessionsCtx, stream]);
if (isFetching) {
setTimeout(() => {
return <LoadingOverlay />;
}, 5000);
}
const onPressHandler = useCallback(
//Callback to open the session
(item) => {
navigation.navigate("Detail", {
sessionID: item.id,
});
},
[onPressHandler]
);
const rightSwipeActions = useCallback(
//Swipe actions for the session list
(item, swipeAnimatedValue) => {
return (
<View
style={{
flexDirection: "row",
width: 168,
height: 132,
}}
>
{item.archived === false ? (
<Pressable
onPress={archiveHandler.bind(this, item)}
style={({ pressed }) => pressed && styles.swipePressed}
>
<View style={styles.archive}>
<Animated.View
style={[
styles.archive,
{
transform: [
{
scale: swipeAnimatedValue.interpolate({
inputRange: [0, 1],
outputRange: [0, 1],
extrapolate: "clamp",
}),
},
],
},
]}
>
<Ionicons
name="ios-archive-outline"
size={24}
color="white"
/>
</Animated.View>
</View>
</Pressable>
) : (
<Pressable
onPress={unArchiveHandler.bind(this, item)}
style={({ pressed }) => pressed && styles.swipePressed}
>
<View style={styles.unArchive}>
<Animated.View
style={[
styles.unArchive,
{
transform: [
{
scale: swipeAnimatedValue.interpolate({
inputRange: [0, 1],
outputRange: [0, 1],
extrapolate: "clamp",
}),
},
],
},
]}
>
<Ionicons
name="md-duplicate-outline"
size={24}
color="white"
/>
</Animated.View>
</View>
</Pressable>
)}
<Pressable
onPress={deleteHandler.bind(this, item)}
style={({ pressed }) => pressed && styles.pressed}
>
<View style={styles.trash}>
<Animated.View
style={[
styles.trash,
{
transform: [
{
scale: swipeAnimatedValue.interpolate({
inputRange: [0, 1],
outputRange: [0, 1],
extrapolate: "clamp",
}),
},
],
},
]}
>
<Ionicons name="trash-outline" size={24} color="white" />
</Animated.View>
</View>
</Pressable>
</View>
);
},
[rightSwipeActions]
);
const deleteHandler = useCallback(
(item) => {
try {
sessionsCtx.deleteSession(item.id); // delete from local context
const uid = auth.currentUser.uid;
const sessionRef = ref(
database,
"users/" + uid + "/sessions/" + item.id
);
remove(sessionRef); // delete from firebase
} catch (error) {
alert(error.message);
}
},
[deleteHandler]
);
const archiveHandler = (item) => {
try {
const id = item.id;
const updatedSession = {
...item, // copy current session
archived: true,
};
const uid = auth.currentUser.uid;
const sessionRef = ref(database, "users/" + uid + "/sessions/" + id);
update(sessionRef, updatedSession);
/* sessionsCtx.updateSession(id, updatedSession); */
//update inbox state
setInbox(
currentSessions.filter((session) => {
const updatedData = session.archived === false;
return updatedData;
})
);
//update archive state
setArchive(
currentSessions.filter((session) => {
const updatedData = session.archived === true;
return updatedData;
})
);
} catch (error) {
alert(error.message);
}
};
const unArchiveHandler = (item) => {
try {
const id = item.id;
const updatedSession = {
...item, // copy current session
archived: false,
};
const uid = auth.currentUser.uid;
const sessionRef = ref(database, "users/" + uid + "/sessions/" + id);
update(sessionRef, updatedSession);
/* sessionsCtx.updateSession(id, updatedSession); */
//update unarchived session list
setArchive((preState) => {
//remove the item from archived list
preState.filter((session) => session.id !== item.id);
return [...preState];
});
} catch (error) {
alert(error.message);
}
};
const selectSessionHandler = useCallback(
(selectedItem) => {
switch (selectedItem) {
case "Sessions":
setStream(inbox);
break;
case "Archive":
setStream(archive);
break;
}
},
[selectSessionHandler, inbox, archive]
);
const selectFilterHandler = (selectedItem) => {
//filter the session list
switch (selectedItem) {
case "ABC":
// Use the Array.sort() method to sort the list alphabetically in ascending order
const sortedList = stream.sort((a, b) => {
return a.title.localeCompare(b.title);
});
setStream((preState) => {
return [...sortedList];
});
break;
case "CBA":
// Use the Array.sort() method to sort the list alphabetically in descending order
const sortedList2 = stream.sort((a, b) => {
return b.title.localeCompare(a.title);
});
setStream((preState) => {
return [...sortedList2];
});
break;
case "Latest Date":
// Use the Array.sort() method to sort the list by date in descending order
const sortedList3 = stream.sort((a, b) => {
return b.date.localeCompare(a.date);
});
setStream((preState) => {
return [...sortedList3];
});
break;
case "Earliest Date":
// Use the Array.sort() method to sort the list by date in ascending order
const sortedList4 = stream.sort((a, b) => {
return a.date.localeCompare(b.date);
});
setStream((preState) => {
return [...sortedList4];
});
break;
}
};
const renderSessionItem = useCallback(({ item }) => {
return (
<Pressable
/* style={({ pressed }) => pressed && styles.pressed} */
onPress={onPressHandler.bind(null, item)}
key={item.id}
>
<SessionComponent
key={item.id}
title={item.title}
identifier={item.identifier}
date={item.date}
rightSwipeActions={rightSwipeActions.bind(null, item)}
smed={item.smed}
endTime={item.endTime}
/>
</Pressable>
);
}, []);
return (
<View style={styles.container}>
<View style={styles.menuRow}>
<SelectBtn
data={sortList}
onSelect={(item) => selectFilterHandler(item)}
/>
<SelectBtn
data={sessionList}
onSelect={(item) => selectSessionHandler(item)}
/>
</View>
<FlatList
data={stream}
renderItem={renderSessionItem}
keyExtractor={(item) => item.id}
extraData={stream}
/>
</View>
);
}
export default SessionStream;
What I already tried:
I tried ChatGPT the whole day yesterday ... ;-)
I tried updating the global state for sessions to trigger re-renders ...
I tried updating the local state as obj or via the spread operator to ...
I tried extraData prop at FlatList
I removed useCallback to make sure it doesnt somehow block ...
can you do this when you are updating your stream state
const oldStream = stream;
const newStream = newStream; // put the value that you have updated
const returnedTarget= Object.assign(stream, newStream);
setStream(returnedTarget);
The problem might be you are mutating the copy obj
ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
c) in your selectFilterHandler method you are updating filter and in the same method you are trying to use updated filter value. which is not possible as useState does not update value immediately.
b) in your archiveHandler i think you are not updating the setStream state. if you are trying to run
const selectSessionHandler = useCallback(
(selectedItem) => {
switch (selectedItem) {
case "Sessions":
setStream(inbox);
break;
case "Archive":
setStream(archive);
break;
}
},
[selectSessionHandler, inbox, archive]
);
this method whenever inbox/archive changes it will not work it will be work only when you call this method and any of the value in dependency array has changed. (you can use useEffect and pass and deps arr [inbox,archive] which will run every time and can update your state.

Markers don't always show up in the MapView of the Map page of my react-native app

There are 4 "parceiros" (partners) registered in the database. Each partner has an address, in the model "Street Ocean View, 182". These addresses are converted to coordinates in the useCoordinates hook. But markers don't always load on the map. I searched for a solution but hard to find someone who has done the same in react-native > 0.69
/src/page/mapa/index.js
import { useState, useEffect } from 'react';
import { View, PermissionsAndroid, Image } from 'react-native';
import BarraPesquisa from '../../components/BarraPesquisa';
import MapView, { Marker } from 'react-native-maps';
import Geolocation from "react-native-geolocation-service";
import useCoordenadas from '../../hooks/useCoordenadas';
import { useNavigation } from '#react-navigation/native';
import markerIcon from '../../assets/images/marker.png';
import { estilos } from './estilos';
export default function Mapa() {
const {coordenadas, carregaCoordenadas} = useCoordenadas();
const [localizacaoAtual, setLocalizacaoAtual] = useState({});
const [permiteGPS, setPermiteGPS] = useState(false);
const [mapReady, setMapReady] = useState(false);
const navigation = useNavigation();
const geolocation = Geolocation;
const requestLocationPermission = async () => {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
{
title: 'Geolocation Permission',
message: 'Can we access your location?',
buttonNeutral: 'Ask Me Later',
buttonNegative: 'Cancel',
buttonPositive: 'OK',
},
);
if (granted === 'granted') {
console.log('Permissão para acesso à geolocalização concedida')
setPermiteGPS(true);
return true;
} else {
console.log('Permissão para acesso à geolocalização não concedida');
return false;
}
} catch (err) {
return false;
}
};
useEffect( () => {
carregaCoordenadas();
requestLocationPermission();
}, [])
useEffect( () => {
permiteGPS && geolocation.getCurrentPosition(
position => {
setLocalizacaoAtual({
latitude: position.coords.latitude,
longitude: position.coords.longitude,
coordinates: {
latitude: position.coords.latitude,
longitude: position.coords.longitude
}
});
},
error => {
console.log(error.message.toString());
},
{
showLocationDialog: true,
enableHighAccuracy: true,
timeout: 20000,
maximumAge: 0
}
);
}, [permiteGPS])
useEffect(() => {
},[coordenadas])
return (
<View>
<BarraPesquisa style={estilos.searchSection} />
{ ( localizacaoAtual !== undefined &&
localizacaoAtual.hasOwnProperty('latitude') &&
localizacaoAtual.hasOwnProperty('longitude')) &&
<MapView
onMapReady={() => setTimeout(() => setMapReady(true), 10000)}
loadingEnabled = {true}
provider="google"
style={estilos.map}
initialRegion={{
latitude: localizacaoAtual.latitude,
longitude: localizacaoAtual.longitude,
latitudeDelta: 0.04,
longitudeDelta: 0.05,
}}
>
{ coordenadas && coordenadas.map((coordenada, i) => {
return (
<Marker
key={i}
tracksViewChanges={!mapReady}
coordinate={{"latitude": coordenada.lat, "longitude": coordenada.lng}}
pinColor={"orange"}
onPress={() => {
navigation.navigate('ParceiroDetalhes', coordenada.detalhes) }}>
<Image source={markerIcon} style={{height: 35, width: 35}}/>
</Marker>
)
})
}
</MapView>
}
</View>
)
}
/src/hooks/useCoordenadas.js
import { useState } from 'react';
import { listaParceiros } from '../services/requisicoes/parceiros';
import Geocode from "react-geocode";
export default function useCoordenadas() {
const [ coordenadas, setCoordenadas ] = useState([]);
const carregaCoordenadas = async () => {
const parceiros = await listaParceiros();
let coordenadasArray = [];
Geocode.setApiKey("MY_API_KEY");
Geocode.setRegion("br");
Geocode.setLanguage("cs");
Geocode.enableDebug(true);
Promise.all(
parceiros.map((parceiro) => {
Geocode.fromAddress(parceiro.Endereco).then(
(response) => {
const location = response.results[0].geometry.location;
if(location.hasOwnProperty('lat') && location.hasOwnProperty('lng')){
coordenadasArray.push({
detalhes: parceiro,
lat: location.lat,
lng: location.lng,
});
}
},
(error) => {
console.error(error);
}
)
})).then(() => {
setCoordenadas(coordenadasArray)
}
)
}
return { coordenadas, carregaCoordenadas };
}

if action.payload.number exist increase state.points with action.payload.points

In React-Native I´ve two TextInputs and an add-button
My add function works i.e it creates a list. But each time I fill out the form, it adds a new listpost. I want to check if action.payload.number exist, and if true, increase state.points with action.payload.points.
as yet everything I tried with have failed i.e it didn't recognize state.number === action.payload.number and adds a new row in the list
Please help me solving this issue
Thanks in advance
Pierre
const InputScreen = () => {
const [number, setNumber] = useState("");
const [points, setPoints] = useState("");
const {addScorer} = useContext(Context);
const onPress = () => {
addScorer(number, points);
setnumber("");
setPoints("");
};
return (
<View>
<Text style={styles.label}>enter Scorer Number:</Text>
<TextInput style={styles.input} value={number} onChangeText={setNumber} />
<Text style={styles.label}>enter Points Scored:</Text>
<TextInput style={styles.input} value={points} onChangeText={setPoints} />
<TouchableOpacity onPress={onPress}>
<FontAwesome5 name="plus-circle" size={44} color="coral" />
</TouchableOpacity>
</View>
);
};
export default InputScreen;
const scorerReducer = (state, action) => {
const id = Date.now().toString().slice(-4);
switch (action.type) {
case "add_scorer":
// if (state.number === action.payload.nummer) {
if (state.find((scorer) => scorer.id === action.payload.id)) {
return [
...state,
{
points: state.points + +action.payload.points,
},
];
} else {
return [
...state,
{
id: id,
number: action.payload.number,
points: +action.payload.points,
},
];
}
default:
return state;
}
};
const addScorer = (dispatch) => {
return (number, points, id) => {
dispatch({type: "add_scorer", payload: {number, points, id}});
};
};
export const {Context, Provider} = createDataContext(
scorerReducer,
{addScorer},
[]
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
I solved it without using Reducer:)
export const ScoredProvider = ({children}) => {
const [playerList, setPlayerList] = useState([]);
const [number, setNumber] = useState("");
const [points, setPoints] = useState("");
const addScorer = () => {
const players = [...playerList];
if (number.trim().length === 0) {
return;
}
const posit = players.map((player) => player.number).indexOf(number);
if (posit !== -1) {
setPlayerList((playerList) =>
playerList.map((scorer, index) =>
index === posit
? {
...scorer,
points: scorer.points + +points,
}
: scorer
)
);
} else {
const newScorer = {
id: Date.now(),
number: number,
points: +points,
};
setPlayerList([...playerList, newScorer]);
setPoints(points);
}
};
return (
<ScoredContext.Provider
value={{number, setNumber, points, setPoints, playerList, addScorer}}
>
{children}
</ScoredContext.Provider>
);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

React Apollo fetch once

Im working on simply COVID-19 tracker and i have a problem.
Is there any option in Apollo for React to fetch graphql data once per button press?
Now i have TextInput and Button but when i fetch data once i can't type another country in input because i have immediately error.
const Tile = () => {
const [country, setCountry] = useState('Poland');
const [cases, setCases] = useState(0);
const MY_QUERY = gql`
query getCountryStats($country: String!) {
country(name: $country) {
todayCases
}
}
`;
const [getCountryStats, {data, loading, error}] = useLazyQuery(MY_QUERY, {
variables: {
country: country,
},
onCompleted: (data) => {
setCases(data.country.todayCases);
},
});
if (loading) return <Text>LOADING...</Text>;
if (error) return <Text>Error!</Text>;
return (
<View>
<CasesNumber>{cases}</CasesNumber>
<FinderWrapper>
<FinderInput
onChangeText={(text) => {
setCountry(text);
}}
/>
<FinderButton
onPress={() => {
getCountryStats();
}}>
<Text>FIND</Text>
</FinderButton>
</FinderWrapper>
</View>
);
};
export default Tile;
Try using this
const Tile = () => {
const [country, setCountry] = useState('Poland');
const [cases, setCases] = useState(0);
let inputValue = ‘’;
const MY_QUERY = gql`
query getCountryStats($country: String!) {
country(name: $country) {
todayCases
}
}
`;
const [getCountryStats, {data, loading, error}] = useLazyQuery(MY_QUERY, {
variables: {
country: country,
},
onCompleted: (data) => {
setCases(data.country.todayCases);
},
});
const onGetCountryStats = () => {
setCountry(inputValue);
getCountryStats();
}
if (loading) return <Text>LOADING...</Text>;
if (error) return <Text>Error!</Text>;
return (
<View>
<CasesNumber>{cases}</CasesNumber>
<FinderWrapper>
<FinderInput
onChangeText={(text) => {
inputValue = text;
}}
/>
<FinderButton
onPress={() => {
onGetCountryStats();
}}>
<Text>FIND</Text>
</FinderButton>
</FinderWrapper>
</View>
);
};
export default Tile;

React Native image picker is showing image too slow after successfully uploading

after uploading image successfully the uploaded image is taking time to show ?
anyone knows anything about it?
here is my code
_onPressEdit = () => {
ImagePicker.showImagePicker(options, response => {
console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled image picker');
} else if (response.error) {
console.log('ImagePicker Error: ', response.error);
} else if (response.customButton) {
console.log('User tapped custom button: ', response.customButton);
} else {
this._uploadImage(response.uri);
}
});
};
here is my full code
import React, {PureComponent} from 'react';
import {View, Text, Image, PermissionsAndroid, Platform} from 'react-native';
import {connect} from 'react-redux';
import ImagePicker from 'react-native-image-picker';
import styles from './styles';
import {Images, Styles, Language, Colors} from '#theme';
import {Wrapper, Input, ButtonView} from '#components';
import {TextInputField} from '#customComponents';
import {Navigator} from '#services';
import StarRating from 'react-native-star-rating';
import Header from '../Header';
import Footer from '../Footer';
import {uploadImage, editProfile} from '../../../actions/UserActions';
import {BASE_URL_PHOTO} from '../../../config/WebService';
import {selectUserData} from '../../../selectors/userSelector';
import {UserPresenter} from '../../../presenter';
import {Util} from '../../../utils';
const options = {
storageOptions: {
skipBackup: true,
path: 'images',
},
};
class Profile extends PureComponent {
constructor(props) {
super(props);
const {firstName, lastName, email, mobile, image, id} = this.props.user;
this.state = {
id,
firstName,
lastName,
email,
mobile,
image,
errors: {},
};
}
onStarRatingPress(rating) {
this.setState({
starCount: rating,
});
}
checkAllPermissions = async () => {
try {
await PermissionsAndroid.requestMultiple([
PermissionsAndroid.PERMISSIONS.CAMERA,
PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE,
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
]);
if (
(await PermissionsAndroid.check('android.permission.CAMERA')) &&
(await PermissionsAndroid.check('android.permission.CAMERA')) &&
(await PermissionsAndroid.check('android.permission.CAMERA'))
) {
this._onPressEdit();
return true;
} else {
console.log('all permissions denied');
return false;
}
} catch (err) {
console.warn(err);
}
};
_onPressEdit = () => {
ImagePicker.showImagePicker(options, response => {
console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled image picker');
} else if (response.error) {
console.log('ImagePicker Error: ', response.error);
} else if (response.customButton) {
console.log('User tapped custom button: ', response.customButton);
} else {
this._uploadImage(response.uri);
}
});
};
_uploadImage = image => {
const {uploadImage} = this.props;
const {id} = this.props.user;
UserPresenter.sendUploadAvatarRequest(
uploadImage,
image,
id,
this._onSuccessImageUpload,
);
};
_onSuccessImageUpload = uri => {
this.setState({
image: uri,
});
};
_onChangeText = (key, value) => {
this.setState(
{
[key]: value,
},
() => console.log(this.state),
);
};
_validateForm = () => {
const {firstName, lastName, mobile} = this.state;
const errors = UserPresenter.getEditProfileErrors(
firstName,
lastName,
mobile,
);
this.setState({errors});
return Util.isEmpty(errors);
};
_onPressSave = () => {
const {firstName, lastName, mobile, image} = this.state;
const {id} = this.props.user;
const {editProfile} = this.props;
if (this._validateForm()) {
UserPresenter.sendEditProfileRequestStepOne(
editProfile,
id,
firstName,
lastName,
mobile,
image,
this._onSuccessSave,
);
}
};
_onSuccessSave = () => {
// Navigator.pop();
Navigator.goBack();
};
_onPressNext = () => {
if (this._validateForm()) {
Navigator.navigate('EditProfileServices', {data: this.state});
}
};
onPressFooterBtn = () => {
Navigator.navigate('EditProfileServices');
};
renderStarRating() {
const {rating} = this.props.user;
return (
<StarRating
starSize={24}
starStyle={styles.starStyle}
halfStarEnabled={true}
halfStarColor={Colors.textWhiteTwo}
emptyStarColor={Colors.textWhiteTwo}
disabled={true}
maxStars={5}
rating={rating}
selectedStar={rating => this.onStarRatingPress(rating)}
/>
);
}
renderEditFields() {
const {firstName, lastName, email, mobile, errors} = this.state;
return (
<View>
<TextInputField
title={Language.firstName}
placeholder={Language.Andrew}
value={firstName}
onChangeText={text => this._onChangeText('firstName', text)}
error={errors.firstName}
/>
<TextInputField
title={Language.lastName}
placeholder={Language.Crammer}
value={lastName}
onChangeText={text => this._onChangeText('lastName', text)}
error={errors.lastName}
/>
<TextInputField
title={Language.email}
keyboardType={'email-address'}
placeholder={Language.andrewCrammerEmail}
value={email}
onChangeText={text => this._onChangeText('email', text)}
error={errors.email}
editable={false}
/>
<TextInputField
title={Language.phone}
keyboardType={'phone-pad'}
placeholder={Language.EditProfilePhonePlaceholder}
value={mobile}
onChangeText={text => this._onChangeText('mobile', text)}
error={errors.mobileNumber}
/>
{/* <Input
label={Language.changePassword}
secureTextEntry={true}
placeholder={Language.EditProfileChangePassword}
/> */}
</View>
);
}
renderBody() {
const {rating} = this.props.user;
const {image} = this.state;
return (
<View style={Styles.paddingHorizontal}>
<View
style={[
Styles.flexDirectionRow,
Styles.alignItemsCenter,
styles.mb_30,
]}>
<View style={styles.editProfileImgWrap}>
<Image
style={styles.imgStyle}
source={{uri: `${BASE_URL_PHOTO}${image}`}}
/>
<ButtonView
isBackgroundRipple
onPress={
Platform.OS === 'android'
? this.checkAllPermissions
: this._onPressEdit
}
style={[Styles.positionAbsolute, styles.editWrap]}>
<Text style={styles.edit}>{Language.edit}</Text>
</ButtonView>
</View>
<View>
<Text style={styles.textStyle}>{Language.ProfilePicture}</Text>
</View>
</View>
<View style={styles.starStyleWrap}>
{this.renderStarRating()}
<Text style={styles.starRatingText}>{rating}</Text>
</View>
<View>{this.renderEditFields()}</View>
</View>
);
}
renderHeader() {
return <Header onPressSave={this._onPressSave} />;
}
renderFooter() {
return <Footer onPressNext={this._onPressNext} step={1} />;
}
//Render
render() {
return (
<Wrapper
header={this.renderHeader()}
footer={this.renderFooter()}
isFetching={this.props.isFetching}
isAbsolute
mainContainerStyle={Styles.paddingHorizontalNone}
isScrollView>
{this.renderBody()}
</Wrapper>
);
}
}
const mapStateToProps = state => {
return {
user: selectUserData(state.user),
isFetching: state.user.isFetching,
};
};
const actions = {uploadImage, editProfile};
export default connect(mapStateToProps, actions)(Profile);
issue solved
just compress your image size so it wont take time to appear
here is the code
const options = {
title: 'Select Picture',
storageOptions: {
skipBackup: true,
path: 'images',
},
maxWidth: 500,
maxHeight: 500,
quality: 0.5,
};
previous code was
const options = {
storageOptions: {
skipBackup: true,
path: 'images',
},
};