Displaying image from firebase in react native (hitting error) - javascript

On one screen I'm taking an image and it's uploading to firebase but on another page when I'm trying to donwload the image to display it i'm hitting an error but the error it goes to something random. If I copy and paste the url into the image src it works.
I can also console log details from the image but for some reason hitting an error displaying it.
export default function DisplayPage() {
const imageRef = firebase.storage().ref().child('images');
const sampleImage = imageRef.getDownloadURL();
return (
<View>
<Image source={{ uri: sampleImage }} style={{ width: 350, height: 350 }} />
</View>
);
}
I'm uploding the file in another page
const ref = firebase
.storage()
.ref()
.child('images')
}
I want to just have a page that displays all of the images in the file that I'm in but I can't even get one image to show up.
What am I doing wrong here?
Edit:
The code error that I get it, it just refers to some random file within expo and prevents the app from booting (hence the reason why I didn't post it) but the response below actually answered my question. The only thing I'm wondering is how would you display an entire folder instead of just one image. Would that go inside of the child()? I have tried it both in child() and ref() and failed at both.
Thank you for all the help!

I have wrapped getDownloadURL method in async because it would take time to get an image from it and the view would be render initially on page load so it wouldn't render the image until it gets from getDownloadURL. So, I have used state for it which renders view again when state reset the image, and this time it loads the image successfully.
export default function DisplayPage() {
const [sampleImage, setSampleImage] = useState(); // set state here
const getSampleImage = async () => {
const imageRef = firebase.storage().ref().child('images');
const url = await imageRef.getDownloadURL().catch((error) => { throw error });
setSampleImage(url);
}
// Similar to componentDidMount and componentDidUpdate:
useEffect(() => {
getSampleImage();
});
return (
<View>
{sampleImage ? <Image source={{ uri: sampleImage }} style={{ width: 350, height: 350 }} /> : null }
</View>
);
}

Related

Error: undefined is not an object (evaluating 'card.image') React-Native

Theres a screen where I show the cards, firstly it shows all the cards without filter and I'm trying to create his functionality of filter but shows this error, HELP ME PLS. The code is this:
const [preferenceSelected, setPreferenceSelected] = useState("");
const [list, setList] = useState(data);
useEffect(() =>{
if(preferenceSelected === ''){
setList(data);
}else{
setList(
data.filter(item => {
if(item.categoria === preferenceSelected){
console.log(list);
return true;
}else{
return false;
}
})
)
}
}), [preferenceSelected];
<View style={styles.EventCards}>
<Swiper
cards={list}
renderCard={(card) => {
return (
<TouchableOpacity style={styles.card} onPress={() => {
navigation.navigate('EventProfile', {
id: card.id,
nome: card.nome,
categoria: card.categoria,
image: card.image,
avaliacao: card.avaliacao,
});
}} >
<Image source={{uri:card.image}} style={styles.cardImg} />
</TouchableOpacity>
);
}}
stackSize={4}
stackSeparation={10}
disableBottomSwipe
disableTopSwipe
verticalSwipe={false}
backgroundColor={"transparent"}
keyExtractor={card => card.id}
></Swiper>
I tried to create his filter method but it always showed an error. And I'm using his dependency to utilize animated card.
I found myself getting this error frequently when trying to call objects in the frontend. I think this error occurs when the frontend loads before the information is called so here are my two workarounds.
To avoid this error I tried two things:
Firstly wrapping the element you're calling in an if statement in your frontend
{card != null ?
<>
//show frontend
</>
: null }
Another good option would be just to use an activity indicator
The other thing I tried was creating another useEffect listener as follows:
const [called, setCalled] = useState(false);
Then once the data is fetched, I set this value to true. Then at the end of my useEffect I added called in the square brackets as a listener.
What this does is refreshes the frontend once that variable changes. I hope this kind of helps

Use AsyncStorage values kept in state and display it

I'm making my first app, "mark what album you've listened" kind of app. I used iTunes search API and for every album listened, I create a key with AsyncStorage using the ID and for the value, the url to the artwork.
So here is the question: I'm stuck at the last step of the app. I want to display all the artwork of all the albums I've listened. For that, I would like to make a foreach loop that for every element in listened, it would take its URL (now that it only contains URLs), put it in an Image tag, return it and display it... But, can I do that?
For that, I created a state called listened. It takes all the AsyncStorage thanks to this function:
importData = async () => {
try {
const keys = await AsyncStorage.getAllKeys();
const result = await AsyncStorage.multiGet(keys);
console.log(result)
//listened takes all asyncstorage data
this.setState({listened: result.map(req => JSON.stringify(req[1]))});
} catch (error) {
console.error(error)
}
}
Then I made a renderArtwork() function that returns the state when I arrive to the Navigation. For now, it just displays all the URLs:
renderArtwork(){
this.importData();
return(
<Text>{this.state.listened}</Text>
)
}
And the "main":
render() {
return(
<View style={styles.main_container}>
{this.renderArtwork()}
</View>
)
}
Thank you for your help
It better to move the importData() to your componentDidMount which will call and get the data from asyncstorage when the screen is mounted.
As for displaying the images, Lets say that your current array 'listened' has the below format
listened = ['url1','url2'];
renderArtwork() {
this.importData();
return this.state.listened.map((url) => (
<Image
style={{
width: 50,
height: 50,
}}
source={{
uri: url,
}}
/>
));
}
You can simply map and show all the images in your array, Also the JSON.stringify part wont be necessary as its already a string.

React Native load data from API using hooks

Im new in ReactNative and I'm trying to take some data from here https://www.dystans.org/route.json?stops=Hamburg|Berlin
When I try console.log results it return full API response. I dont know why in first results.distance works and return distance, but when I'm trying to do it inside FlatList nothing is returned. Sometimes it works when i want to return only item.distance but can't somethnig like <Text>{item.stops[0].nearByCities[0].city}</Text> nowhere in my code also in console. Im getting error:
undefined is not an object (evaluating 'results.stops[0]')
imports...
const NewOrContinueScreen = ({ navigation }) => {
const [searchApi, results, errorMessage] = useDystans();
console.log(results.distance);
return (
<SafeAreaView forceInset={{ top: "always" }}>
<Text h3 style={styles.text}>
Distance: {results.distance}
</Text>
<Spacer />
<FlatList
extraData={true}
data={results}
renderItem={({ item }) => (
<Text>{item.distance}</Text>
// <Text>{item.stops[0].nearByCities[0].city}</Text>
)}
keyExtractor={item => item.distance}
/>
<Spacer />
</SafeAreaView>
);
};
const styles = StyleSheet.create({});
export default NewOrContinueScreen;
And here is my hook code:
import { useEffect, useState } from "react";
import dystans from "../api/dystans";
export default () => {
const [results, setResults] = useState([]);
const [errorMessage, setErrorMessage] = useState("");
const searchApi = async () => {
try {
const response = await dystans.get("route.json?stops=Hamburg|Berlin", {});
setResults(response.data);
} catch (err) {
setErrorMessage("Something went wrong with useDystans");
}
};
useEffect(() => {
searchApi();
}, []);
return [searchApi, results, errorMessage];
};
As the name implies, FlatList is designed to render a list. Your API endpoint returns a JSON Object, not an Array, so there's nothing for the FlatList to iterate. If you want to show all the stops in the list, try passing in the stops list directly.
<FlatList
data={results.stops}
renderItem={({ item }) => (<Text>{item.nearByCities[0].city}</Text>)}
/>
Some side notes: (1) The extraData parameter is used to indicate if the list should re-render when a variable other than data changes. I don't think you need it here at all, but even if you did, passing in true wouldn't have any effect, you need to pass it the name(s) of the variable(s). (2) The keyExtractor parameter is used to key the rendered items from a field inside of them. The stop objects from the API don't have a member called distance so what you had there won't work. From my quick look at the API response, I didn't see any unique IDs for the stops, so you're probably better off letting React key them from the index automatically.

How to wait for a promise when receiving an image from Firestore?

I am making an app using React Native and store information about users in a collection called "User" on Firestore. Each user has a profile picture url stored in the collection, and I want to display multiple user images on the same page. I am struggling, however, to get this to work due to having to wait for Promises to return.
I have tried storing the url in a state variable when it is retrieved, however, this would involve creating loads of state variables due to the number of images I want to display. I then tried using async/await and then statements but the images won't load due to the promises not returning in time.
async getImg(user_id) {
return await firebase.firestore().collection('User').doc(user_id).get()
.then(user => {return user.data().image})
render() {
<SafeAreaView style={styles.container}>
<Image source={{uri: this.getImg('rwWa39Y6xtS1nZguswugODWndqx2') }} style={{ ... }} />
<Image source={{uri: this.getImg('HQkCoChUe5fkZrHypYdRnrw66Rp2') }} style={{ ... }} />
</SafeAreaView>
);
}
The above code is my latest attempt and it returns the following error due to a promise being returned instead of the string url.
You attempted to set the key `_65` with the value `1` on an object that is meant to be immutable and has been frozen.
Does anyone have any idea of how to solve this?
You are mixing the use of async/await with the then() method.
By doing as follows:
async getImg(user_id) {
const userSnapshot = await firebase.firestore().collection('User').doc(user_id).get()
return userSnapshot.data().image;
}
you will declare an asynchrnous getImg() function.
I don't know react-native so I don't know if it would work by using it in
<Image source={{uri: this.getImg('rwWa39Y6xtS1nZguswugODWndqx2') }} style={{ ... }} />
But #VolkanSahin45 solution, adapted as follows, should work:
async getImg(user_id) {
const userSnapshot = await firebase.firestore().collection('User').doc(user_id).get()
this.setState({
img: userSnapshot.data().image;
})
}
Note that it would be good to handle errors with try/catch as follows:
async getImg(user_id) {
try {
const userSnapshot = await firebase.firestore().collection('User').doc(user_id).get()
this.setState({
img: userSnapshot.data().image;
})
} catch (error) {
this.setState({
img: 'default_user_img.png';
})
}
}
getImg function returns Promise. Instead you can save img to state and render if there is img.
async getImg(user_id) {
return await firebase.firestore().collection('User').doc(user_id).get()
.then(user => {
this.setState({
img: user.data().image
})
}
)
}
render() {
const { img } = this.state;
return(
<SafeAreaView style={styles.container}>
img && <Image source={{ img }} style={{ ... }} />
</SafeAreaView>
)
}

Task orphaned for request in react-native – what does it mean?

I am trying to build a grid system for tiles with buttons and other actions. I forked trying with the react native playground grid images source, that you can find here. It produces the following "stacktrace" and error when adding zIndex to individual pics. Images are never portrayed.
In case you are interested this is the exact component I am using:
export default class GridLayout extends Component {
constructor () {
super()
const { width, height } = Dimensions.get('window')
this.state = {
currentScreenWidth: width,
currentScreenHeight: height
}
}
handleRotation (event) {
var layout = event.nativeEvent.layout
this.setState({ currentScreenWidth: layout.width, currentScreenHeight: layout.height })
}
calculatedSize () {
var size = this.state.currentScreenWidth / IMAGES_PER_ROW
return { width: size, height: size }
}
renderRow (images) {
return images.map((uri, i) => {
return (
<Image key={i} style={[styles.image, this.calculatedSize()]} source={{uri: uri}} />
)
})
}
renderImagesInGroupsOf (count) {
return _.chunk(IMAGE_URLS, IMAGES_PER_ROW).map((imagesForRow) => {
console.log('row being painted')
return (
<View key={uuid.v4()} style={styles.row}>
{this.renderRow(imagesForRow)}
</View>
)
})
}
render () {
return (
<ScrollView style={styles.grid} onLayout={(ev) => this.handleRotation(ev)} contentContainerStyle={styles.scrollView}>
{this.renderImagesInGroupsOf(IMAGES_PER_ROW)}
</ScrollView>
)
}
}
var styles = StyleSheet.create({
grid: {
flex: 1,
backgroundColor: 'blue'
},
row: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'flex-start',
backgroundColor: 'magenta'
},
image: {
zIndex: 2000
}
})
It may have something to do with the way you are rendering. Your request seems to get stuck. It looks like this is the code where the error is thrown in RN (from RCTImageLoader.m):
// Remove completed tasks
for (RCTNetworkTask *task in _pendingTasks.reverseObjectEnumerator) {
switch (task.status) {
case RCTNetworkTaskFinished:
[_pendingTasks removeObject:task];
_activeTasks--;
break;
case RCTNetworkTaskPending:
break;
case RCTNetworkTaskInProgress:
// Check task isn't "stuck"
if (task.requestToken == nil) {
RCTLogWarn(#"Task orphaned for request %#", task.request);
[_pendingTasks removeObject:task];
_activeTasks--;
[task cancel];
}
break;
}
}
I'm not exactly sure how to solve this, but a couple ideas to help you debug:
The <Image> component has some functions and callbacks that you could utilize to try to further track down the issue (onLoad, onLoadEnd, onLoadStart, onError, onProgress). The last two are iOS only but you could see if any of those are called to see where in the process things get hung up.
Alternatively, the way I would do this would be to use a ListView and place the image urls in the datasource prop for the ListView (utilizing the _.chunk method to group them as you already do). This would be a little cleaner way of rendering them IMO
I think this issue is possibly related to you trying to load http images in ios. I get this same error in my project when using faker images in my seed data on ios (android doesn't care) which only come back with http. Here's a better explanation that I found on this topic React-native loading image over https works while http does not work
according to react native, it better to have the item component a pure component and all the data to be rendered in the component should be in the item object itself for better performance. In case of image I also dont know how they are handling it. loading image from url might be something which is not in the item object itself. However, i am also getting the issue and I am calling a function to load an image icon which are packed with application.

Categories