【问题标题】:Importing components throws "Invalid hook call. Hooks can only be called inside of the body of a function component." error导入组件抛出“无效的钩子调用。只能在函数组件的主体内部调用钩子。”错误
【发布时间】:2022-06-15 03:09:57
【问题描述】:

我正在尝试实现一个多选下拉菜单,而我找到的每个组件(材质 UI、反应选择等)最终都会引发此错误:

“无效的钩子调用。只能在函数组件的主体内部调用钩子。”

我已经从我的依赖项中删除了 React 和 React-dom 并将它们添加为 peerDependencies。我还从服务器和客户端中删除了 node_modules 和包锁,并安装了 npm,但没有运气。

我是一个新开发者,所以还在搞清楚这一切,任何帮助将不胜感激!谢谢你:)

import React, { useEffect, useState } from 'react';
import axios from 'axios';

import Select from 'react-select'

import { catchErrors } from '../utils';
import { getCurrentUserPlaylists } from '../spotify';

import '../styles/Playlists.css'


const Playlists = () => {
  const [playlists, setPlaylists] = useState();
  const [topSongs, setTopSongs] = useState();
  const [selectedOption, setSelectedOption] = useState(null);

  const options = playlists?.items.map(playlist => {
    const container = {};
    container.value = playlist.name
    container.label = playlist.name
    return container
  })

  useEffect(() => {
    // getCurrentUserPlaylists returns a promise, we must use await to wait for the promise to be resolved -- we handle this by creating an async fn 
    const fetchData = async () => {
      const { data } = await getCurrentUserPlaylists();

      setPlaylists(data);
    };

    fetchData();

    // handles errors from async fn 
    catchErrors(fetchData());

  }, []);

  // create array of playlist IDs > use playlist ID array to create endpoint array 
  let playlistIds = Object.values(checkedPlaylists)
  let playlistEndpoints = playlistIds.map(id => `/playlists/${id}`);

  // function to run after submit button is clicked
  // grabs selected playlists' data, counts duplicate records and sets the top songs state array
  const handleSubmit = (event) => {
    event.preventDefault();

    let allTracks = {};

    // concurrent GET requests using axios for each endpoint 
    const getTracks = async () => {
      
      // playlists = array of playlist objects
      const playlists = await axios.all(playlistEndpoints.map((endpoint) => axios.get(endpoint)));

      // loop through each playlist
      for (let playlist of playlists) {

        // playlist.data.tracks.items = array of track objects
        let trackArr = playlist.data.tracks.items; 

        for (const song of trackArr) {
          if (allTracks[song.track.id]) {
            allTracks[song.track.id][1] += 1
          } else {
            allTracks[song.track.id] = [song.track.name, 1, song.track.album.images[2].url,song.track.artists[0].name]
          }
        }
      }

      // create array of song.name/count arrays
      const allTracksArr = Object.values(allTracks);

      // create new array that's sorted by highest to lowest count
      const sortedTracks = allTracksArr.sort((a, b) => b[1] - a[1]);
  
      // set top songs state array and slice it at 20 element
      setTopSongs(sortedTracks.slice(0,10));
    }
    catchErrors(getTracks());
  }

  return (
    <>
      <h2 id='page-title'>Playlist Analysis</h2>
      <div className='content-container'>
        <div className='form-wrapper'>
          <h2 className='titles'>Select Playlists</h2>
          <form onSubmit={handleSubmit} className='form'>
            <Select 
              defaultValue={selectedOption}
              onChange={setSelectedOption}
              options={options} 
              isMulti
              name='playlists'
            />
            <button className='submit-btn' type='submit'>Analyze</button>
          </form>
        </div>
        {topSongs && 
          <div className='topsongs-list-wrapper'>
            <h2 className='titles' id='topsongs-title'>Top Songs</h2>
            <div className='topsongs-container'>
              {topSongs?.map((topSong, index)=> {
                  return (
                    <div key={topSong+index} role="row" className='track-row-wrapper'>
                      <div className='track-row'>
                        <div className='rank-number'><strong>{index + 1}</strong></div>
                        <div className='album-cover'><img className='album-cover-img' src={topSong[2]} alt='Album Cover'/></div>
                        <div className='track'>
                          <div className='track-title'>{topSong[0]}</div>
                          <div className='track-artist'>{topSong[3]}</div>
                        </div>
                        <div className='count-number'>{topSong[1]}</div>
                      </div>
                    </div>
                  )
              })}
            </div>
          </div>
        }
      </div>
    </>
  )
}

export default Playlists;```

【问题讨论】:

  • 将 fetchData 的函数声明移到 useEffect 之外,它不会解决问题,但它的 anipattern
  • 您真的要调用fetchData 两次吗? `catchErrors(fetchData());` 中的第二个调用似乎是拼写错误
  • 错误调用堆栈——它指向哪里?
  • 从“react”导入 React,{useState,useEffect}

标签: javascript reactjs react-hooks


【解决方案1】:

我认为你应该导入 react 和 useState 钩子

【讨论】:

  • 我有,我只是在复制/粘贴代码时错过了它——不过谢谢!
猜你喜欢
  • 2019-11-21
  • 2021-10-31
  • 2021-03-23
  • 2020-10-27
  • 2020-02-14
  • 2022-11-27
  • 2021-11-11
  • 2020-01-28
  • 1970-01-01
相关资源
最近更新 更多