I'm new to react native and I'm not able to consume this api, when I start this app in the browser, it works fine, but when I go to the expo app it doesn't display the pokemon image, could someone help me?
import { StatusBar } from 'expo-status-bar';
import React, { useEffect, useState } from 'react';
import { StyleSheet, Text, View, Button, Alert, TextInput, Image } from 'react-native';
interface PokeInterface {
sprites : {
back_default : string;
}
}
export default function App() {
const [text, setText] = useState<string>("")
const [response, setResponse] = useState<PokeInterface | any>()
const [image, setImage] = useState<string>()
const handleText = (text : string) => {
setText(text)
}
const searchApi = (pokemonName : string) => {
fetch(`https://pokeapi.co/api/v2/pokemon/${pokemonName}/`, { method: 'GET'})
.then((response) => response.json())
.then((response) => setResponse(response))
}
useEffect(() => {
if(text){
searchApi(text)
}
if(response){
const {sprites} = response
setImage(sprites.front_default)
}
return () => {
if(image){
setImage("")
}
}
},[text, response])
return (
<View style={styles.container}>
<View style={styles.topbar}>
<Text style={styles.title}>Pokedex Mobile</Text>
<TextInput
style={styles.input}
onChangeText={(value: any) => handleText(value)}
value={text}
placeholder="Search Pokemon"
keyboardType="default"
/>
<Text style={styles.text}>{text}</Text>
</View>
{image && (
<Image
style={styles.logo}
source={{uri : `${image}`}}
/>
)}
</View>
);
}
const styles = StyleSheet.create({
text : {
fontSize: 30,
color : "red"
},
input: {
height: 40,
margin: 12,
borderWidth: 1,
padding: 10,
},
container : {
flex: 1,
alignItems: 'center',
justifyContent: 'center'
},
title: {
fontSize: 30,
color: '#000'
},
topbar: {
},
logo : {
width: 200,
height: 200
}
});
CodePudding user response:
Your current code causes an infinite loop...
- You type some text which triggers
searchApi(text)
- That writes to
response
which triggers your effect hook - Because
text
is still truthy, it triggerssearchApi(text)
again - Goto #2
As far as I can tell, you can simply discard most of response
and just retrieve the image when the text changes.
// this doesn't need to be defined in your component
const getPokemonImage = async (name: string) => {
const res = await fetch(
`https://pokeapi.co/api/v2/pokemon/${encodeURIComponent(pokemonName)}/`
);
if (!res.ok) {
throw new Error(`${res.status}: ${await res.text()}`);
}
return (await res.json<PokeInterface>()).sprites.front_default;
};
export default function App() {
const [text, setText] = useState<string>("");
const [image, setImage] = useState<string>(""); // initial value
const handleText = (text: string) => {
setText(text);
};
useEffect(() => {
if (text) {
getPokemonImage(text).then(setImage);
}
}, [ text ]); // only run on text change
CodePudding user response:
import React, {useEffect, useState} from 'react';
import {StyleSheet, Text, View, TextInput, Image, Button} from 'react-native';
// Sorry for removing the types i was using JS
// This code works test it for yourself
export default function App() {
const [text, setText] = useState('');
const [response, setResponse] = useState(); // Here use PokeInterface || any as you are doing conditional checking
const [image, setImage] = useState();
const handleText = e => {
setText(e);
};
const searchApi = pokemonName => {
fetch(`https://pokeapi.co/api/v2/pokemon/${pokemonName}/`, {method: 'GET'})
.then(response => response.json())
.then(response => setResponse(response));
};
useEffect(() => {
if (response) {
const {sprites} = response;
console.log(response);
setImage(sprites.front_default);
}
return () => {
if (image) {
setImage('');
}
};
}, [image, text, response]); // you have to pass all the dependencies so useEffect will be invoked as you didnt pass image dep the useeffct was not invoking
return (
<View style={styles.container}>
<View style={styles.topbar}>
<Text style={styles.title}>Pokedex Mobile</Text>
<TextInput
style={styles.input}
onChangeText={(value: any) => handleText(value)}
value={text}
placeholder="Search Pokemon"
keyboardType="default"
/>
<Text style={styles.text}>{text}</Text>
</View>
{image && <Image style={styles.logo} source={{uri: `${image}`}} />}
<Button
title={'Submit'}
onPress={() => searchApi(text)}
disabled={!text}
/>
</View>
);
}
const styles = StyleSheet.create({
text: {
fontSize: 30,
color: 'red',
},
input: {
height: 40,
margin: 12,
borderWidth: 1,
padding: 10,
},
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
title: {
fontSize: 30,
color: '#000',
},
topbar: {},
logo: {
width: 200,
height: 200,
},
});