【问题标题】:Setting image src dynamically in reactJS在 reactJS 中动态设置图像 src
【发布时间】:2021-05-17 15:13:31
【问题描述】:

我正在尝试在 reactJS 中动态设置图像 src,我正在使用 typescript,关于图像的代码如下。

这只是我的一段代码,展示了我在更新应用中的天气图标时尝试遵循的逻辑。

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

  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;
`;

【问题讨论】:

  • 请突出显示您面临的问题。
  • 问题是当我在输入字段中输入新位置时,我的页面上的图标没有改变
  • 在 fetchData 函数中将 yoyr setIcon 更改为此 setIcon(response.data.weather[0].icon)

标签: html reactjs typescript react-hooks styled-components


【解决方案1】:

问题:useEffect 依赖项

您的useEffect 具有Icon 作为依赖项,但它也设置了Icon。因此,每次更改图标时,它都会再次运行。这种设置有可能出现无限循环。目前发生的情况是,总是以 sun 结束 default 案例,因为无论何时将其设置为其他值,它都会触发使用新值重新运行。

解决方案 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));
});

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

【讨论】:

    猜你喜欢
    • 2021-12-06
    • 2018-12-09
    • 2014-09-01
    • 2019-09-02
    • 1970-01-01
    • 2021-11-21
    • 1970-01-01
    • 1970-01-01
    • 2018-10-07
    相关资源
    最近更新 更多