【发布时间】: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