首页 > 解决方案 > ReactJS 在接收到要渲染的数据之前调用渲染方法

问题描述

当主组件加载时,我向我的 API 发送一个 GET 请求,以获取在名为 的字段中具有特定值的所有对象"ship_name",这意味着可能会到达更多“构建”,因此将有更多需要渲染。加载主组件后,我在同一个文件中创建了第二个组件,称为“Builds”。作为道具,我向这个组件发送对象数组 this.state.builds。

更好的解释:

  1. 用户在搜索栏中插入“ship_name”
  2. API 查找具有该“ship_name”的所有构建
  3. 所有构建都发送到子组件
  4. 使用“gears”(齿轮名称)API 查找文件名并将其发送回
  5. !在链接到达之前反应渲染
<Builds builds={this.state.builds} />

“构建”的结构是这样的

[
    {
        "gears": [
            "Triple 410mm (10th Year Type Prototype)",
            "Triple 155mm (3rd Year Type)",
            "Twin 40mm Bofors STAAG Mk II",
            "High Performance Fire Control Radar",
            "Type 1 Armor Piercing Shell"
        ],
        "rarities": [
            "o",
            "o",
            "o",
            "o",
            "o"
        ],
        "_id": "5eac7b450e64096b082f4c43",
        "ship_name": "Gascogne",
        "pv": "e"
    },
    {
        "gears": [
            "Triple 410mm (10th Year Type Prototype)",
            "Triple 155mm (3rd Year Type)",
            "Twin 40mm Bofors STAAG Mk II",
            "High Performance Fire Control Radar",
            "Type 1 Armor Piercing Shell"
        ],
        "rarities": [
            "o",
            "o",
            "o",
            "o",
            "o"
        ],
        "_id": "5f131d6e2e3f16ef3de48e4f",
        "ship_name": "Gascogne",
        "pv": "e"
    }
]

到目前为止一切正常。

render() {
        return (
            this.props.builds.map((build) => (
                <div className="container" key={uuidv4()}>
                    <img src={"/img/gears/" + this.getGearData(build.gears[0])} className={build.rarities[0] + " gI g1"}></img><div className={"t t1"}>{build.gears[0]}</div>
                    <img src={"/img/gears/" + this.getGearData(build.gears[1])} className={build.rarities[1] + " gI g2"}></img><div className={"t t2"}>{build.gears[1]}</div>
                    <img src={"/img/gears/" + this.getGearData(build.gears[2])} className={build.rarities[2] + " gI g3"}></img><div className={"t t3"}>{build.gears[2]}</div>
                    <img src={"/img/gears/" + this.getGearData(build.gears[3])} className={build.rarities[3] + " gI g4"}></img><div className={"t t4"}>{build.gears[3]}</div>
                    <img src={"/img/gears/" + this.getGearData(build.gears[4])} className={build.rarities[4] + " gI g5"}></img><div className={"t t5"}>{build.gears[4]}</div>
                </div>
            ))

        )
    }

/*------------------------------*/

getGearData(gear_name) {
        let requestString = encodeURI('http://localhost:5000/gears/one?q=' + gear_name)
        let data;
        Axios.get(requestString)
            .then(res => {
                console.log(res.data[0].image_link)
                data = res.data[0].image_link
            })

        return data

        /* what */
    }

这里发生的是,在我渲染的同时,我试图获取图像的 URL。GET 方法有效,实际上 console.log 打印文件的实际名称

32200.png gear.component.js:76 
26600.png gear.component.js:76 
1260.png gear.component.js:76 
600.png gear.component.js:76 
34180.png gear.component.js:76 

但在 SRC 上,结果是"/img/gears/undefined"。我无法理解的一件事是为什么所有结果都打印了 2 次,但这并不是什么大问题,因为最终这些东西只能正确渲染一次。

我尝试过使用许多方法、状态、Promises(即使我还没有真正理解它们是如何工作的),这是我第一次真正陷入这样的困境。事实上,主要组件使用“ship_name”来获取“ship_icon”和“faction_icon”的文件名,这没有问题,可能是因为我使用了那里的状态。

这是一个关于它现在的样子的想法

这是一个关于它应该是什么样子的想法

我曾经使用 php 和 SQL 完成了这个个人项目,现在我正在尝试使用 React 和 MongoDB 来完成。

标签: javascriptreactjs

解决方案


注意:您应该首先在检索和/或设置构建的过程中调用获取图像 URL,这种数据结构是设计不佳的标志;现在,那说:

  1. React 是一个反应式库。它只对正在监视的数据的变化做出反应。

  2. 您不能混合使用异步和同步函数并期望一切都等待。

当你打电话给这里时,这是按发生顺序发生的getGearData(gear_name)事情的粗略概述

  1. getGearData用变量调用gear_name
  2. 一个可修改的变量requestString被声明并设置为encodeURI('http://localhost:5000/gears/one?q=' + gear_name)(旁注,这应该是const因为它没有被修改
  3. data声明了一个可修改的变量
  4. 启动异步请求以从服务器检索数据
  5. 对 的当前值的引用data返回给调用者
  6. 反应渲染
  7. 您的请求完成
  8. 局部变量函数范围内data设置

你必须等待异步操作

有很多方法可以做到这一点。这是使用占位符图像的示例

const placeholder = "https://link.to/placeholder-image.png"

class MyComponent extends Component {

  constructor(props) {
    super(props)
    this.state = { images: {} }
  }
  componentDidUpdate(prevProps) {
    if(prevProps.builds != this.props.builds) {
      this.fetchImages()
    }
  }

  fetchImages() {
    this.props.builds.forEach(build => {
      build.gears.forEach(gear => {
        Axios.get(encodeURI('http://localhost:5000/gears/one?q=' + gear_name))
          .then(res => {
            const link = res.data[0].image_link 
            console.log(link)
            this.setState(state => { images: { ...state.images, [gear]: link } })
          })
      })
    })
  }

  mapGears = (gears) =>
    gears.map(
      (gear, i) =>
        <img
          src={this.state.images[gear] || placeholder}
          className={`t t${i}`}
          key={`${gear}.${i}`}
        />
    )

  render() {
    return (
      this.props.builds.map((build) => (
        <div className="container" key={build._id}>
          {this.mapGears(build.gears)}
        </div>
      ))
    }
}

推荐阅读