如何使用React Redux动态渲染图标



我正在创建一个播放列表,我想显示我最喜欢的曲目"用不同的图标,比如一颗心填充,默认渲染一个有边框的心。基本上默认代码是工作的,但当刷新页面时,图标填充消失并呈现默认值。如果有人有什么建议,我是react的新手,不知道我是否可以有很多"useStates"像这样。

我忘了说,应用程序正在使用Redux-persist,所以页面刷新后信息继续在商店中。这就是为什么我要显示基于商店信息填充的图标

import React, { useState, useEffect } from "react";
import ReactDOMServer from "react-dom/server";
import axios from "axios";
import { useSelector, useDispatch } from "react-redux";
import { ListContainer, PlayerStyle, InfoBox } from "./style.jsx";
import FavoriteBorderIcon from "@material-ui/icons/FavoriteBorder";
import FavoriteIcon from "@material-ui/icons/Favorite";
import PlayCircleOutlineIcon from "@material-ui/icons/PlayCircleOutline";
import PauseCircleOutlineIcon from "@material-ui/icons/PauseCircleOutline";
import MusicPlayer from "../MusicPlayer/index";
const List = () => {
const [isLoading, setLoading] = useState(true);
const [valueList, setValueList] = useState(20);
const [search, setSearch] = useState("");
const [dataList, setDataList] = useState([]);
const [trackList, setTrackList] = useState([]);
const [bannerAlbum, setBannerAlbum] = useState("");
const [createdBy, setCreatedBy] = useState("");
const [isPlayed, setIsPlayed] = useState(false);
const [musicPlayed, setMusicPlayed] = useState("");
const [showTrackList, setShowTrackList] = useState(true);
const [showFavoriteList, setShowFavoriteList] = useState(false);
const [favoriteData, setFavoriteData] = useState([]);
const favoriteList = useSelector(
(state) => state.FavoriteListReducer.favorites
);
const dispatch = useDispatch();
let chartPlaylist = `https://api.deezer.com/playlist/1111141961?&limit=${valueList}`;
useEffect(() => {
axios.get(chartPlaylist).then((res) => {
// console.log(res.data, "album");
setDataList(res.data);
setTrackList(res.data.tracks.data);
setBannerAlbum(res.data.picture_medium);
setCreatedBy(res.data.creator.name);
// Ao terminar a requisição dos dados, mostra os componentes
setLoading(false);
});
}, [chartPlaylist]);
useEffect(() => {
axios.all(favoriteList.map((l) => axios.get(l))).then(
axios.spread(function (...res) {
// all requests are now complete
setFavoriteData(res);
})
);
if (!showTrackList && favoriteList.length === 0) {
setShowTrackList(true);
setShowFavoriteList(false);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [favoriteList]);
const handleInput = (e) => {
setSearch(e.target.value);
};
const handlePlayed = () => {
if (!isPlayed) {
setIsPlayed(true);
} else {
setIsPlayed(false);
}
};
const handleIconSwap = (e) => {
e.currentTarget.firstElementChild.innerHTML = ReactDOMServer.renderToString(
!isPlayed ? <PlayCircleOutlineIcon /> : <PauseCircleOutlineIcon />
);
};
const Add_fav = (e) => {
dispatch({
type: "ADD_FAV",
newId: `https://api.deezer.com/track/${e.currentTarget.getAttribute(
"value"
)}`,
});
e.currentTarget.firstElementChild.innerHTML = ReactDOMServer.renderToString(
favoriteList.includes(e.currentTarget.getAttribute("value")) ? (
""
) : (
<FavoriteIcon style={{ color: "red" }} />
)
);
};
const Del_fav = (e) => {
dispatch({
type: "DELETE_FAV",
remove: `https://api.deezer.com/track/${e.currentTarget.getAttribute(
"value"
)}`,
});
e.currentTarget.firstElementChild.innerHTML = ReactDOMServer.renderToString(
favoriteList.includes(e.currentTarget.getAttribute("value")) ? (
""
) : (
<FavoriteBorderIcon fontSize={"inherit"} />
)
);
};
// eslint-disable-next-line no-array-constructor
const handleFav = (e) => {
favoriteList.includes(
`https://api.deezer.com/track/${e.currentTarget.getAttribute("value")}`
)
? Del_fav(e)
: Add_fav(e);
};
const toggleData = () => {
if (showTrackList && favoriteList.length > 0) {
setShowTrackList(false);
setShowFavoriteList(true);
}
if (!showTrackList) {
setShowTrackList(true);
setShowFavoriteList(false);
}
};
if (isLoading) {
return <div>Loading...</div>;
}
return (
<>
<button
onClick={() => {
if (valueList < 100) {
setValueList(valueList + 20);
}
}}
>
adicionar +20 musicas
</button>
<br />
<br />
<br />
<button
onClick={() => {
toggleData();
}}
>
Mostrar Favoritos
</button>
<InfoBox>
<input
type="text"
value={search}
onChange={(e) => setSearch(e.target.value)}
/>
<div className="content">
<img src={bannerAlbum} alt="" />
<div className="Info--desc">
<h1>{dataList.title}</h1>
<div>
<span>criado por: </span>
{createdBy}
</div>
</div>
</div>
</InfoBox>
<ListContainer>
<div className="headerList">
<div className="rank">#</div>
<div className="favorite--icon">
{/* <FavoriteBorderIcon fontSize={"inherit"} /> */}
</div>
<div className="title--music">FAIXA</div>
<div className="title--artist">ARTISTA</div>
<div className="title--album">ALBUM</div>
<div className="title--duration">D.</div>
</div>
<div className="bodyList">
{showTrackList &&
trackList.map((item, key) => {
return (
<>
<div
key={key}
onMouseEnter={handleIconSwap}
onMouseLeave={(e) => {
if (!isPlayed) {
e.currentTarget.firstElementChild.innerHTML = key + 1;
} else {
e.currentTarget.firstElementChild.innerHTML =
ReactDOMServer.renderToString(
<PauseCircleOutlineIcon />
);
}
}}
>
<div
className="rank"
onClick={() => setMusicPlayed(trackList[key].preview)}
>
{key + 1}
</div>
<div className="favorite--icon">
// Here that has to dynamically render 
<span value={item.id} onClick={(e) => handleFav(e)}>
<Icon favIco={false} />
</span>
</div>
<div className="title--music">
<a target="_blank" rel="noreferrer" href={item.link}>
{item.title}
</a>
</div>
<div className="title--artist">{item.artist.name}</div>
<div className="title--album">{item.album.title}</div>
<div className="title--duration">
{item.duration / 60 < 10
? "0" +
(item.duration / 60)
.toFixed(2)
.toString()
.replace(".", ":")
: (item.duration / 60)
.toFixed(2)
.toString()
.replace(".", ":")}
</div>
</div>
</>
);
})}
</div>
</ListContainer>
</>
);
};
const Icon = (props) => {
switch (props.favIco) {
case true:
return <FavoriteIcon style={{ color: "red" }} />;
case false:
return <FavoriteBorderIcon fontSize={"inherit"} />;
default:
return <FavoriteBorderIcon fontSize={"inherit"} />;
}
};
export default List;

我的Reducer商店工作得很好,只是在加载页面时没有渲染填充的心脏,如果我点击心脏并从商店中删除信息并再次点击图标更改为填充。

const initialState = {
favorites: [],
};
const List = (state = initialState, action) => {
switch (action.type) {
case "ADD_FAV":
return { ...state, favorites: [...state.favorites, action.newId] };
case "DELETE_FAV":
let index = state.favorites.indexOf(action.remove);
if (index > -1) {
state.favorites.splice(index, 1);
}
return {
...state,
favorites: [...state.favorites],
};
default:
}
return state;
};
export default List;

谢谢大家

我在你上面的评论中看到,你目前使用redux-persist来保持在重新加载之间的存储,所以访问数据不是问题。

看你的代码,我认为问题可能是你渲染图标的方式。

如果我理解正确的话,这是由Add_fav函数完成的:

const Add_fav = (e) => {
dispatch({
type: "ADD_FAV",
newId: `https://api.deezer.com/track/${e.currentTarget.getAttribute(
"value"
)}`,
});
e.currentTarget.firstElementChild.innerHTML = ReactDOMServer.renderToString(
favoriteList.includes(e.currentTarget.getAttribute("value")) ? (
""
) : (
<FavoriteIcon style={{ color: "red" }} />
)
);
};

但是这个函数只在您添加一个新的收藏夹时运行——因此重载后没有图标,因为这部分代码根本不会运行。

我的建议是将图标呈现逻辑更改为组件的返回JSX,而不是在事件处理函数中。像这样:

<span value={item.id} onClick={(e) => handleFav(e)}>
{ 
favoriteList.includes(item.id) 
? <FavoriteIcon style={{ color: "red" }} /> 
:  <FavoriteBorderIcon fontSize={"inherit"} /> 
}
</span>

所以我被发送到商店是一个字符串在渲染逻辑搜索一个int数,然后编辑函数添加方法parseInt()

const Add_fav = (e) => {
dispatch({
type: "ADD_FAV",
newId: parseInt(e.currentTarget.getAttribute("value")),
});
};

,现在工作正常,因为逻辑正在搜索Number Int。

<span value={item.id} onClick={(e) => handleFav(e)}>
{ 
favoriteList.includes(item.id) 
? <FavoriteIcon style={{ color: "red" }} /> 
:  <FavoriteBorderIcon fontSize={"inherit"} /> 
}
</span>

最新更新