React .map不是一个函数。

7
我是一个初学者,正在尝试学习 React 和 JavaScript。现在我正在开发一个从 Flickr API 获取数据的应用程序。问题是,在 Main.js 组件中尝试对 props 使用 map 方法时,我会收到以下错误:"Uncaught TypeError: this.props.photos.map is not a function"。在 Stackoverflow 上搜索后,我认为问题是 this.props 是 JavaScript 对象而不是数组。问题是我不知道如何将它转换为数组。有人可以解释一下我做错了什么吗?
我的代码:
class App extends Component {

  constructor() {
  super();
  this.state = {

  }
}

componentDidMount() {

let apiKey = 'xxxxxxxxxxxxxxxxxx';
let searchKeyword = 'nature';
let url = `https://api.flickr.com/services/ 
           rest/?api_key=${apiKey}&method=flickr.photos.
           search&format=json&nojsoncallback=1&&per_page=50
           &page=1&text=${searchKeyword}`;

fetch(url)
  .then(response => response.json())
  .then(data => data.photos.photo.map((x) => {

    this.setState({
      farm: x.farm,
      id: x.id,
      secret: x.secret,
      server: x.server})
   // console.log(this.state)
  }))
 }

    render() {
      return (
        <div className="App">
          <Header />
          <Main img={this.state.photos} />
          <Navigation />
        </div>
      );
    }
  }

  export default class Main extends Component {

  render() {

    return(
      <main className="main">
        {console.log(this.props.photos)}
      </main>
    )
  }
 }

编辑:

为什么this.props.img一开始是未定义的?

控制台输出console.log(this.props.img)的截图


什么是 photomapArray 的一个方法。 - Davin Tryon
我收到一个错误,提示“未捕获的类型错误:this.props.photos.map不是一个函数”。在你引用的代码中没有出现 this.props.photos.map 的字样。但是,data.photos.photo.map 出现了,请问你是指它吗? - T.J. Crowder
1
分开来看:你正在调用map,在map回调函数内部,你正在调用setState并且没有返回任何值,所以你将每个条目映射为undefined;而且你根本没有使用map的返回值(你返回了它,但没有任何东西使用该promise,所以它未被使用)。你几乎肯定不想这样重复调用setState - T.J. Crowder
URL是否真的有换行符?那样做可能无法正常工作。 - Patrick Roberts
3个回答

7
fetch(url)
  .then(response => response.json())
  .then(data => data.photos.photo.map((x) => {

    this.setState({
      farm: x.farm,
      id: x.id,
      secret: x.secret,
      server: x.server})
  }))

正在发生的是您在Promise中的映射函数对每个返回的照片重新设置了组件的状态。因此,您的状态始终是返回的照片列表中的最后一个对象。

这是我所提到的更简化的示例:

const testArray = [1,2,3,4];

let currentState;

testArray.map((value) => currentState = value)

console.log(currentState);

你想要做的是这样的

const testArray = [1,2,3,4];

let currentState;

//Notice we are using the return value of the map function itself.
currentState = testArray.map((value) => value)

console.log(currentState);

对于您想要实现的目标,您希望您的状态是map函数的结果(因为它返回映射结果的数组)。可以像这样实现:

fetch(url)
  .then(response => response.json())
  .then(data => 
    this.setState({
      photos:
        data.photos.photo.map((x) => ({
          farm: x.farm,
          id: x.id,
          secret: x.secret,
          server: x.server
        }))
     })
   )

谢谢您的回答。当我尝试在Main组件中使用map方法来处理this.props时,仍然会收到“map不是一个函数”的错误消息。我的目标是为this.state中的每个对象创建一个新的img标签。
{this.props.photos.map((x) => { return })}
- Tose
如果你在控制台输入this.props.photos,它会返回什么? - Nick Wyman
1
一个对象列表。问题是它不是一个数组吗? 对象 {0: 对象,1: 对象,2: 对象,3: 对象,4: 对象,5: 对象,6: 对象,7: 对象,8: 对象,9: 对象,10: 对象,11: 对象,12: 对象,13: 对象,14: 对象,15: 对象,16: 对象,17: 对象,18: 对象,19: 对象,20: 对象,21: 对象,22: 对象,23: 对象,24: 对象,25: 对象,26: 对象,27: 对象,28: 对象,29: 对象,30: 对象,31: 对象,32: 对象,33: 对象,34: 对象,35: 对象,36: 对象,37: 对象,38: 对象} - Tose
深入挖掘后,看起来React的状态需要是一个对象。我已经更新了我的解决方案底部以反映这一点。基本上,只需将数组添加到属性中并将该属性传递给您的子组件即可。 - Nick Wyman
非常感谢您的帮助,对于所有的问题我深表歉意。当我尝试进行映射时,仍然会出现相同的错误。这可能是因为在第一次中this.props.img未定义(请参见我第一个问题底部上传的图像)?请注意,我已将属性名称从photos更改为img。 - Tose
很可能是这样。一开始它未定义的原因是因为您的fetch函数是异步的。所以发生的情况是,在fetch函数完成之前,您的App组件已经被渲染了。这就是您未定义结果的来源。一旦fetch完成,它会填充状态并重新渲染您的App组件。那就是第二个控制台日志。您可以通过以下两种方式解决此问题。1.在App组件构造函数中将状态中的数组设置为空数组。2.更新Main组件以处理this.props.img中可能未定义的值。 - Nick Wyman

1

如果您尝试提供除了.map()期望的数组之外的其他内容,即使您正确声明变量类型,也可能会出现此错误。以下是一个基于hook的示例:

const [myTwinkies, setMyTwinkies] = useState<Twinkies[]>([]);

useEffect(() => {
  // add a twinky if none are left in 7eleven
  // setMyTwinkies(twinkiesAt711 ?? {}); // ---> CAUSES ".map is not a function"
  setMyTwinkies(twinkiesAt711 ?? [{}]); 
}, [twinkiesAt711, setMyTwinkies]);

return (<ul>
  {myTwinkies.map((twinky, i)=> (
    <li key={i}>Twinky {i}: {twinky?.expiryDate}</li>
  ))}
</ul>)

0

在进行映射之前,只需检查数组的长度。如果长度大于0,则进行映射,否则忽略它。

data.photos.photo.map.length>0 && data.photos.photo.map(........)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接