在reactJS中动态设置图像src



我试图在reactJS中动态地设置一个图像src,我使用typescript,代码如下:

这只是我的代码的一部分,展示了我试图在我的应用程序中更新天气图标的逻辑。

请,如果你有其他的意见,不要害羞分享他们,我将非常乐意接受任何建设性的批评,但主要是请帮助解决我在这里遇到的主要问题。

const [Icon, setIcon] = useState("");
useEffect(() => {
switch (Icon.substr(0, 2)) {
case "01":
setIcon(sun);
break;
case "50":
setIcon(fog);
break;
case "09":
setIcon(drizzle);
break;
case "11":
setIcon(storm);
break;
case "09" || "13" || "10":
setIcon(rain);
break;
case "13":
setIcon(snow);
break;
case "02" || "03" || "04":
setIcon(clouds);
break;
default:
setIcon(sun);
}
}, [Icon]);

return(<img src={Icon} />)

——完整代码----

import React, { useState, useEffect } from "react";
import styled from "styled-components";
import Header from "../components/Header";
import Footer from "../components/Footer";
import axios from "axios";
import Clock from "react-live-clock";
import Loading from "../components/PageLoader";
import rain from "../images/rain.svg";
import drizzle from "../images/drizzle.svg";
import fog from "../images/fog.svg";
import clouds from "../images/cloud.svg";
import snow from "../images/snowflake.svg";
import storm from "../images/storm.svg";
import sun from "../images/sun.svg";
export default function Home() {
let cityName: string;
const [city, setCity] = useState("amman");
const [Icon, setIcon] = useState("");
const changeC = document.getElementById("C");
const changeF = document.getElementById("F");
const [triggerEffect, setTriggerEffect] = useState(0);
const textChange = (event: any) => {
cityName = event.target.value;
};
const [weatherData, setWeatherData] = useState(Object);
const time = Date();
useEffect(() => {
const fetchData = async () => {
await axios
.get(`http://localhost:5000/app/weather?address=${city}`)
.then((response) => {
setWeatherData(response.data);
setIcon(response.data.weather["0"].icon);
});
};
fetchData();
}, [triggerEffect]);
const [celsius, setCelsius] = useState(true);
const onSubmitText = (event: any) => {
event.preventDefault();
setTriggerEffect(triggerEffect + 1);
if (cityName) {
setCity(cityName);
}
};
function convertCels() {
setCelsius(true);
console.log(changeF + " " + changeC);
if (changeC && changeF) {
changeC.style.color = "#0000ff";
changeF.style.color = "000000";
}
}
function convertFeh() {
setCelsius(false);
console.log(changeF + " " + changeC);
if (changeC && changeF) {
changeC.style.color = "#000000";
changeF.style.color = "0000ff";
}
}
useEffect(() => {
switch (Icon.substr(0, 2)) {
case "01":
setIcon(sun);
break;
case "50":
setIcon(fog);
break;
case "09":
setIcon(drizzle);
break;
case "11":
setIcon(storm);
break;
case "09" || "13" || "10":
setIcon(rain);
break;
case "13":
setIcon(snow);
break;
case "02" || "03" || "04":
setIcon(clouds);
break;
default:
setIcon(sun);
}
}, [Icon]);
return weatherData["name"] && Icon ? (
<MainContainer>
<Header />
<SearchBoxDiv>
<Button type="submit" onClick={onSubmitText}></Button>
<SearchBox
id="text"
type="text"
placeholder="Location"
onChange={textChange}
></SearchBox>
</SearchBoxDiv>
<MainMidContainer>
<SecMidContainer>
<Vector src={Icon} />
</SecMidContainer>
<SecMidContainer>
<CityName>{weatherData["name"]}</CityName>
<Time>
{time.toString().substr(0, 3) + " "}
<Clock format={"HH:mm"} ticking={true} timezone={"Asia/Amman"} />
</Time>
<Condition>{weatherData.weather["0"].description}</Condition>
<Temp id="temp">
{celsius
? parseInt(weatherData.main["temp"]) - 270 + " C"
: parseInt(
parseInt(weatherData.main["temp"]) * (9 / 5) - 459 + "",
) + " F"}
{"   "}
<SuperScriptC
onClick={() => {
convertCels();
}}
>
C
</SuperScriptC>
{"   "}
<SuperScriptF
id="F"
onClick={() => {
convertFeh();
}}
>
F
</SuperScriptF>
</Temp>
</SecMidContainer>
</MainMidContainer>
<Footer />
</MainContainer>
) : (
<Loading />
);
}
const MainContainer = styled.div`
width: 1400px;
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
`;
const SearchBoxDiv = styled.form`
width: 500px;
height: 55px;
display: flex;
align-self: center;
`;
const SearchBox = styled.input`
width: 497px;
height: 54px;
background: #ffffff;
border: 1px solid #000000;
box-sizing: border-box;
padding: 15px;
`;
const MainMidContainer = styled.div`
width: 900px;
heigh: 330px;
display: flex;
flex-direction: row;
justify-content: space-between;
align-self: center;
`;
const SecMidContainer = styled.div`
width: 40%;
height: 330px;
display: flex;
flex-direction: column;
`;
const Vector = styled.img`
height: 330px;
width: 330px;
`;
const CityName = styled.p`
font-family: Roboto;
font-style: normal;
font-weight: 900;
font-size: 40px;
line-height: 47px;
`;
const Time = styled.p`
font-family: Roboto;
font-style: normal;
font-weight: normal;
font-size: 40px;
line-height: 47px;
`;
const Condition = styled.p`
font-family: Roboto;
font-style: normal;
font-weight: normal;
font-size: 30px;
line-height: 35px;
`;
const Temp = styled.p`
font-family: Roboto;
font-style: normal;
font-weight: normal;
font-size: 100px;
line-height: 117px;
margin-top: 15 %;
`;
const SuperScriptC = styled.sup`
font-family: Roboto;
font-style: normal;
font-weight: normal;
font-size: 40px;
line-height: 47px;
`;
const SuperScriptF = styled.sup`
font-family: Roboto;
font-style: normal;
font-weight: normal;
font-size: 40px;
line-height: 47px;
`;
const Button = styled.input`
background-color: transparent;
color: transparent;
border: none;
`;

问题:useEffect Dependencies

您的useEffectIcon作为依赖,但它也设置Icon。所以每次它改变图标的时候,它都会再次运行。这种设置有可能产生无限循环。目前发生的事情是,它总是在default的情况下结束sun,因为每当您将其设置为其他东西时,它都会触发带有新值的重新运行。

解决方案1:更好的依赖

weatherData改变时,我们想重置Icon。而不是调用setIcon(response.data.weather["0"].icon)(删除那一行),我们使用数据中的图标来触发效果。数据已经以weatherData的状态存储。

// you need to fix your initial value of weatherData, but I think this will work
const weatherIcon = weatherData?.weather?.[0]?.icon;
useEffect(() => {
switch (weatherIcon.substr(0, 2)) {
case "01":
setIcon(sun);
break;
/* ... */
}
}, [weatherIcon]);

方案2:纯函数

我们只是根据API响应中的string值选择一个图标。这并不一定是一种效果。我们可以定义一个函数来查找给定string的图标,并在适当的时候自己调用该函数。这个函数也使你不必多次编写break,因为我们正在调用return

const findIcon = (weatherIcon: string) => {
switch (weatherIcon.substr(0, 2)) {
case "01":
return sun;
case "50":
return fog;
/* ... */
default:
return sun;
}
}

您可以在fetch效果中调用此函数并删除图标更新效果。

.then((response) => {
setWeatherData(response.data);
setIcon(findIcon(response.data.weather["0"].icon));
});

你的代码还有其他一些问题,但这应该可以解决图标的问题。

最新更新