为什么这个 React 组件需要很长时间才能重新渲染,有没有更好的写法?
Why is this react component taking ages to re-render, is there a better way of writing this?
我有点受困于当前的项目,它是我的第一个大型 React 项目,所以我认为这里可能缺少一些简单的东西。我决定使用 hooks 因为它看起来更好写,虽然我在尝试用 class 组件重写它时遇到了同样的问题。
基本上我有一个页面应该显示音乐专辑和这些专辑中歌曲的 links,当 links 被点击时 link 应该放一个 spotify iframe 进入DOM。但是当点击发生时,需要很长时间,有时需要 10 秒才能在页面上显示差异
代码:
import React, { useState, useEffect } from 'react'
import FullWidthBanner from './FullWidthBanner';
import Axios from 'axios';
const Song = (props) => {
return (
<div>
<div className={(props.active) ? "songContainer" : "songContainer colourTransition"}>
<div onClick={() => { props.handleClick(props.name); }} style={{ 'backgroundColor': props.color, "zIndex": (props.active) ? "250" : "300" }} className="songTitle">
<h1>{(props.active) ? "LOADING" : props.name}</h1>
</div>
{(props.active || props.clickCount) ? <iframe src={props.src} style={{ "zIndex": (props.active) ? "300" : "250" }} width="300" height="380" frameborder="0" allowtransparency="true" allow="encrypted-media"></iframe> : null}
</div>
</div>
)
}
const Album = (props) => {
const [songs, setSongs] = useState(props.songs);
const handleClick = (name) => {
for (var key in songs) {
songs[key].active = 0;
}
let activeSong = songs.filter((song) => {
return song.name == name;
});
let index = songs.indexOf(activeSong[0]);
songs[index].active = 1;
songs[index].clickCount++;
setSongs(songs);
}
return (
<div className="alContainer">
{songs.map((song) => {
return (
<Song {...song} handleClick={handleClick} />
)
})}
</div>
)
}
const AlbumMeta = (props) => {
return (
<div className="albumMetaContainer">
<img src={props.artwork} width="200" height="200" alt={"The album artwork for Sam Malcolm's album " + props.name} />
<div className="infoContainer">
<h1>{props.name} <i>{props.year}</i></h1>
<p>{props.description}</p>
<div>
{(props.spotifyLink) ? <a style={{ 'borderColor': props.highlight }} href={props.spotifyLink} target="_blank" className="smBtn" >View on Spotify</a> : null}
{(props.itunesLink) ? <a style={{ 'borderColor': props.highlight }} href={props.itunesLink} target="_blank" className="smBtn" >View on iTunes</a> : null}
</div>
</div>
</div>
)
}
const Albums = (props) => {
const [albums, setAlbums] = useState([]);
useEffect(() => {
Axios.get('/api/albums').then((response) => {
setAlbums(response.data);
})
}, [])
return (
<div className="albumsContainer">
<FullWidthBanner caption="Photo: Joe Bloggs" backgroundPosition="top center" src="/path/to/image.jpg" title="Music" />
{albums.map((album) => {
return (
<div>
<AlbumMeta {...album} highlight={props.highlight} />
<Album {...album} />
</div>
)
})}
</div>
)
}
export default Albums
我觉得有更好的写法。有趣的是,当我从 useEffect 中删除第二个参数时,这会导致无限循环,当我单击时页面会立即更新,这很奇怪。
看看这个https://codesandbox.io/embed/magical-leaf-hw8r4
我更改了一些小东西并在其中添加了一些评论。这个对我有用。 iframe 在 1-2 秒内加载歌曲。
我有点受困于当前的项目,它是我的第一个大型 React 项目,所以我认为这里可能缺少一些简单的东西。我决定使用 hooks 因为它看起来更好写,虽然我在尝试用 class 组件重写它时遇到了同样的问题。
基本上我有一个页面应该显示音乐专辑和这些专辑中歌曲的 links,当 links 被点击时 link 应该放一个 spotify iframe 进入DOM。但是当点击发生时,需要很长时间,有时需要 10 秒才能在页面上显示差异
代码:
import React, { useState, useEffect } from 'react'
import FullWidthBanner from './FullWidthBanner';
import Axios from 'axios';
const Song = (props) => {
return (
<div>
<div className={(props.active) ? "songContainer" : "songContainer colourTransition"}>
<div onClick={() => { props.handleClick(props.name); }} style={{ 'backgroundColor': props.color, "zIndex": (props.active) ? "250" : "300" }} className="songTitle">
<h1>{(props.active) ? "LOADING" : props.name}</h1>
</div>
{(props.active || props.clickCount) ? <iframe src={props.src} style={{ "zIndex": (props.active) ? "300" : "250" }} width="300" height="380" frameborder="0" allowtransparency="true" allow="encrypted-media"></iframe> : null}
</div>
</div>
)
}
const Album = (props) => {
const [songs, setSongs] = useState(props.songs);
const handleClick = (name) => {
for (var key in songs) {
songs[key].active = 0;
}
let activeSong = songs.filter((song) => {
return song.name == name;
});
let index = songs.indexOf(activeSong[0]);
songs[index].active = 1;
songs[index].clickCount++;
setSongs(songs);
}
return (
<div className="alContainer">
{songs.map((song) => {
return (
<Song {...song} handleClick={handleClick} />
)
})}
</div>
)
}
const AlbumMeta = (props) => {
return (
<div className="albumMetaContainer">
<img src={props.artwork} width="200" height="200" alt={"The album artwork for Sam Malcolm's album " + props.name} />
<div className="infoContainer">
<h1>{props.name} <i>{props.year}</i></h1>
<p>{props.description}</p>
<div>
{(props.spotifyLink) ? <a style={{ 'borderColor': props.highlight }} href={props.spotifyLink} target="_blank" className="smBtn" >View on Spotify</a> : null}
{(props.itunesLink) ? <a style={{ 'borderColor': props.highlight }} href={props.itunesLink} target="_blank" className="smBtn" >View on iTunes</a> : null}
</div>
</div>
</div>
)
}
const Albums = (props) => {
const [albums, setAlbums] = useState([]);
useEffect(() => {
Axios.get('/api/albums').then((response) => {
setAlbums(response.data);
})
}, [])
return (
<div className="albumsContainer">
<FullWidthBanner caption="Photo: Joe Bloggs" backgroundPosition="top center" src="/path/to/image.jpg" title="Music" />
{albums.map((album) => {
return (
<div>
<AlbumMeta {...album} highlight={props.highlight} />
<Album {...album} />
</div>
)
})}
</div>
)
}
export default Albums
我觉得有更好的写法。有趣的是,当我从 useEffect 中删除第二个参数时,这会导致无限循环,当我单击时页面会立即更新,这很奇怪。
看看这个https://codesandbox.io/embed/magical-leaf-hw8r4
我更改了一些小东西并在其中添加了一些评论。这个对我有用。 iframe 在 1-2 秒内加载歌曲。