来自 Cloud Storage 的图像未在 .map 列表中重新渲染

IT技术 javascript reactjs react-native google-cloud-storage firebase-storage
2021-04-12 15:23:33

我正在从我的 Firebase Cloud Firestore 获取 .map 中的帖子列表。我也有连接到每个帖子的照片,我使用post.title + '.jpg'from Cloud Storage获取它们帖子标题很吸引人,但是在使用时fetchImage它没有显示在帖子中。它显示在 console.log 中。我也可以从控制台访问 url,所以没有错。

有任何想法吗?

{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
      }}
    />
  )}
)}
3个回答

我怀疑目前这个函数返回 Text 和 Image 组件,从服务器获取图像的Promise尚未解决——因此没有显示任何内容,一旦Promise完成,组件就不会重新呈现。

在 React 组件中获取外部资源的典型方法是使用类 Component/PureComponent 语法,在 componentDidMount 钩子中分派获取请求,并将 promise 返回的数据保存在 state 中(使用 this.setState)。

渲染函数应该基于 state 中的值进行渲染——这样一旦 state 用获取的值更新,组件将使用获取的数据重新渲染。

怎么能做到这一点?
2021-06-11 15:23:33

什么是 ReactJS this.props.items.map 属性?

这应该可以帮助您理解使用“map”方法来遍历和显示代表 ReactJS 组件的相似对象列表的概念。标题“this.props.items.map”可以是任何其他映射方法,例如“this.props.profiles.map”,下面有示例,其中配置文件或项目表示数组。它可用于创建列表、表格等。

以下是本文的要点:

  • Map 不是 ReactJS 的特性
  • 在 this.props.profiles.map 的上下文中查看使用“map”的代码示例

在查看了这个ReactJS 教程页面上提供的教程后,其中引用了 .map 来显示 Comment 对象,人们可能会感到困惑,并认为“map”是 ReactJS 的一个特性。事实上,这是一个标准的 JavaScript 函数,可以在任何数组上调用

如果您使用过 Python(应用方法)或 R(lapply 方法)等语言,您可能已经使用“map”作为传递函数的方法,该函数的参数表示存储在数组中的对象的引用。当“map”被调用时,该函数被应用于存储在数组中的每个对象。“map”返回一个由对象组成的新数组,这些对象可能是使用传递数组的对象创建的

一般语法是: array.map(func)

其中 func 应采用一个参数。

如上文所述,array.map 的返回值是另一个数组。

在 this.props.profiles.map 的上下文中使用“map”的代码示例

在下面的示例中,请注意以下一些事项:

  • 有两个组件,例如 UserProfiles 和 Profile
  • 配置文件组件用于表示由名称和国家/地区属性组成的实际配置文件。
  • 顾名思义,UserProfiles 用于表示一个或多个配置文件并呈现配置文件组件。
  • 请注意, UserProfiles 传递了一个 json 对象,例如 profilesJson,它由以 JSON 对象形式表示的配置文件组成。
  • UserProfiles 的 render 方法显示使用“map”方法创建的“allProfiles”变量。反过来,“map”方法返回一个数组 Profile 对象。

以下是以下代码示例在 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>

下载 URL 是异步加载的。要了解这意味着什么,请放置一些日志语句:

console.log("Before calling getDownloadURL")
firebase
.storage()
.ref(post.title + '.jpg')
.getDownloadURL()
.then((url) => {
  console.log("Got URL")
});
console.log("After calling getDownloadURL")

当您运行此代码时,您会得到:

在调用 getDownloadURL 之前

调用 getDownloadURL 后

得到网址

这可能不是您期望的输出顺序。但它完全解释了为什么您return没有返回下载 URL:它尚未加载。

then()从你的调用回调getDownloadURL运行return的组件使用uri: fetchImage并且您不能返回尚未加载的值。

React 中的常见解决方案是存储异步加载到组件状态中的任何数据。

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)
  });
})

由于任何调用都会setState()强制组件重新渲染自身,因此新渲染将从状态中获取更新的下载 URL。

return (
  <Text>{post.title}</Text>
  <Image
    style={styles.image}
    source={{
    uri: this.state[post.title+"_url"]
    }}
  />
现在它起作用了!谢谢!但是,我可以说的是,它的加载速度非常慢。这可能是因为文件大小吗?
2021-05-23 15:23:33
这似乎不起作用。我可以为列表中的每个项目设置一个状态,这真的可能吗?
2021-05-24 15:23:33
@vemund 请遵循此示例.. 并在状态中设置 url。我希望它有效:) 如果您仍然需要我的帮助..我会写出完整的解决方案。快乐编码... reactjs.org/docs/faq-ajax.html
2021-06-18 15:23:33
@vemund setState 将无法在内部访问,因为它超出了范围。根据关闭规则。
2021-06-19 15:23:33
糟糕,我忘记打电话了setState我刚刚补充说。
2021-06-21 15:23:33