简体   繁体   English

访问JavaScript数组返回“未定义”

[英]Accessing JavaScript Array returns “undefined”

I'm building a simple app in pure Reactjs. 我正在用纯Reactjs构建一个简单的应用程序。 Component I'm having problems is a component that is supposed to render a number of buttons by mapping an array that has previously been populated by fetching some data from an external API. 我遇到问题的组件是应该通过映射一个以前通过从外部API提取一些数据来填充的数组来呈现许多按钮的组件。 This array is populated within a class method and the results are eventually copied onto another array which is part of the state of the component 此数组填充在类方法中,结果最终复制到另一个数组中,该数组是组件状态的一部分

When I console.log the contents of the array on the render method of my component, everything looks fine. 当我用console.log在组件的render方法上记录数组的内容时,一切看起来都很好。 However if I try to print a specific element by its index, "undefined" is printed on the console. 但是,如果我尝试通过其索引打印特定元素,则控制台上会打印“ undefined”。 As a result the map function does not render all the desired buttons. 结果,地图功能无法呈现所有所需的按钮。

I have managed to find different documentation around the way I'm populating the array but none of the articles so far suggest that I'm doing anything fundamentally wrong. 在填充数组的方式上,我设法找到了不同的文档,但是到目前为止,没有一篇文章表明我在做任何根本上错误的事情。 At least not that I can see. 至少我看不到。

State stores an empty array to start with and within the componentWillMount method an API gets called that fetches data and updates the array as per the below: State存储一个空数组,以componentWillMount方法开头,并在componentWillMount方法内调用一个API,该API会按以下所述获取数据并更新该数组:

this.state = {
      resources: []
}

getAPIavaiableResources(api_resource) {
    let buttonsArray = []
    fetch(api_resource)
      .then(response => response.json())
      .then(data => {
        for (let i in data) {
          buttonsArray.push({id: i, name: i, url: data[i]})
        }
      }).catch(error => console.log(error))

    this.setState({resources: buttonsArray})
}

componentWillMount() {
    this.getAPIavaiableResources(ROOT_RESOURCE)
}

render() {
    const { resources } = this.state;
    console.log(resources)
    console.log(resources[0])

    return (
      <div className="buttons-wrapper">
        {
          resources.map(resource => {
            return <Button
                      key={resource.id}
                      text={resource.name} 
                      onClick={this.handleClick} 
                    />
          })
        }
      </div>
    )
}

This is what gets printed onto the console on the render method. 这就是在render方法上打印到控制台上的内容。

[]
0: {id: "people", name: "people", url: "https://swapi.co/api/people/"}
1: {id: "planets", name: "planets", url: "https://swapi.co/api/planets/"}
2: {id: "films", name: "films", url: "https://swapi.co/api/films/"}
3: {id: "species", name: "species", url: "https://swapi.co/api/species/"}
4: {id: "vehicles", name: "vehicles", url: "https://swapi.co/api/vehicles/"}
5: {id: "starships", name: "starships", url: "https://swapi.co/api/starships/"}
length: 6
__proto__: Array(0)

Can anyone see what I'm doing wrong? 谁能看到我在做什么错? I'm pushing an object because I do want an array of objects albeit arrays in Javascript are objects too. 我要推送一个对象是因为我确实想要一个对象数组,尽管Javascript中的数组也是对象。 Any help would be appreciated. 任何帮助,将不胜感激。

Your current implementation is setting state before you have the data, and then mutating state once the api call comes back. 当前的实现方式是在获取数据之前先设置状态,然后在api调用返回后再更改状态。 React can't tell when you mutate things, and thus doesn't know to rerender. React无法分辨您何时进行更改,因此不知道要重新渲染。 Only when you call setState (or when it receives new props) does it know to rerender. 仅当您调用setState(或当它收到新的道具)时,它才知道要重新渲染。

Instead, wait until you have the data and only then call setState with the populated array. 相反,请等到拥有数据,然后再使用填充的数组调用setState。

getAPIavaiableResources(api_resource) {
  fetch(api_resource)
    .then(response => response.json())
    .then(data => {
      let buttonsArray = []
      for (let i in data) {
        buttonsArray.push({id: i, name: i, url: data[i]})
      }
      this.setState({resources: buttonsArray})
    }).catch(error => console.log(error))
}

componentDidMount() {
    this.getAPIavaiableResources(ROOT_RESOURCE)
}

The above example also updates the code to use componentDidMount instead of componentWillMount. 上面的示例还更新了代码,以使用componentDidMount而不是componentWillMount。 componentWillMount is deprecated, and wasn't intended for this sort of case anyway. componentWillMount已弃用,无论如何都不打算用于这种情况。

Currently you are setting the state without waiting for the promise to be resolved. 当前,您正在设置状态,而无需等待承诺被解决。 In order to do that, move this.setState({resources: buttonsArray}) after for loop. 为此,请在for循环后移动this.setState({resources: buttonsArray})

In addition, you can render the component conditionally until the you get what you want from the remote resource by doing: 另外,您可以有条件地渲染组件,直到通过执行以下操作从远程资源获得所需的内容:

render () {
  const { resources } = this.state;
  return resources.length
    ? (
      <div>Your content...</div>
    )
    : null // or some loader
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM