问题
I am making a list of posts in a .map fetching from my Firebase Cloud Firestore. I also have photos connecting to each post, and I fetch them by using the post.title + '.jpg'
from Cloud Storage. The post title is fetching great, but when using the fetchImage
it is not showing in the post. It is showing in the console.log. I can also access the url from the console, so nothing wrong there.
Any ideas?
{this.state.posts.map((post, i) => {
let fetchImage
firebase
.storage()
.ref(post.title + '.jpg')
.getDownloadURL()
.then((url) => {
console.log(url)
fetchImage = url;
});
return (
<Text>{post.title}</Text>
<Image
style={styles.image}
source={{
uri: fetchImage
}}
/>
)}
)}
回答1:
I suspect that at the moment this function returns Text and Image components the promise which gets the images from the server is not yet resolved -- and thus nothing is displayed and the component doesn't re-render once the promise is done.
The typical way of fetching external resources in a React component is to use the class Component/PureComponent syntax, dispatch a fetch request in componentDidMount hook and save the data returned by the promise in state (using this.setState).
The render function should render based on the values in state -- so that once state is updated with the fetched value, the component will re-render using the fetched data.
回答2:
What is the ReactJS this.props.items.map Property?
This should help you understand the concepts around the usage of the “map” method to traverse and display a list of similar objects representing a component in ReactJS. The title “this.props.items.map” could be any other map method, such as “this.props.profiles.map” which has examples below where profiles or items represent an array. It could be used to create a list, table, etc.
Here are the main points of this article:
- Map is NOT a feature of ReactJS
- See a code sample using “map” in the context of this.props.profiles.map
After looking at the tutorial provided on this ReactJS tutorials page where the reference of .map is made to display Comment objects, one may get confused and think that “map” is a ReactJS feature. As a matter of fact, this is a standard JavaScript function which could be called on any array
If you have worked on languages such as Python (apply method), or R (lapply method), you've probably used “map” as a method to pass a function with a parameter representing the reference of an object stored in an array. When “map” is called, the function is applied to each of the objects stored in the array. The “map” returns a new array consisting of objects which might be created using objects of the passed array
The general syntax is: array.map(func)
where func should take one parameter.
As mentioned in text above, the return value of array.map is another array.
Code sample using “map” in the context of this.props.profiles.map
In the example below, notice some of the following things:
- There are two components such as UserProfiles and Profile
- Profile component is used to represent actual profile comprising of name and country attributes.
- UserProfiles, as it sounds, is used to represents one or more profile and renders Profile components.
- Note that UserProfiles is passed a json object such as profilesJson which consists of profiles represented in form of JSON object.
- render method of UserProfiles displays “allProfiles” variable which is created using “map” method. The “map” method, in turn, returns an array Profile object.
Following is how the below code sample would be displayed on HTML:
<div id="content"></div>
<script type="text/jsx">
var profilesJson = [
{name: "Pete Hunt", country: "USA"},
{name: "Jordan Walke", country: "Australia"}];
var Profile = React.createClass({
render: function(){
return(
<div>
<div>Name: {this.props.name}</div>
<div>Country: {this.props.country}</div>
<hr/>
</div>
);
}
});
var UserProfiles = React.createClass({
render: function(){
var allProfiles = this.props.profiles.map(function(profile){
return (
<Profile name={profile.name} country={profile.country} />
);
});
return(
<div>{allProfiles}</div>
);
}
});
React.render( <UserProfiles profiles={profilesJson}/>, document.getElementById( "content"));</script>
回答3:
The download URL is loaded asynchronously. To see what this means, place a few log statements:
console.log("Before calling getDownloadURL")
firebase
.storage()
.ref(post.title + '.jpg')
.getDownloadURL()
.then((url) => {
console.log("Got URL")
});
console.log("After calling getDownloadURL")
When you run this code you get:
Before calling getDownloadURL
After calling getDownloadURL
Got URL
This is probably not the order you expected the output in. But it completely explains why your return
does not return the download URL: it hasn't been loaded yet.
The then()
callback from your call to getDownloadURL
runs after you return
the component that uses uri: fetchImage
. And you can't return a value that hasn't loaded yet.
The common solution in React is to store any data that is asynchronously loaded into the component's state.
this.state.posts.map((post, i) => {
let fetchImage
firebase
.storage()
.ref(post.title + '.jpg')
.getDownloadURL()
.then((url) => {
let state = {};
state[post.title+"_url"] = url
this.setState(state)
});
})
Since any call to setState()
forces the component to rerender itself, the new render will then pick up the updated download URL from the state.
return (
<Text>{post.title}</Text>
<Image
style={styles.image}
source={{
uri: this.state[post.title+"_url"]
}}
/>
来源:https://stackoverflow.com/questions/52836115/image-from-cloud-storage-is-not-redendring-in-map-list