无法渲染来自 API 的图像

Not able to render image from API

我能够从 API 端点获取数据,但无法将其呈现到屏幕上。

这是我的 App.js 组件。

    function App() {
  const [data, setData] = useState([]);
      const [img, setImg] = useState([]);

    

  useEffect(() => {
    fetchData(setData);
  }, []);

  async function fetchImage(name) {
    const requestOptions = {
      method: "GET",
      redirect: "follow",
    };
   await fetch(
      `https://avatars.dicebear.com/v2/avataaars/${name}.svg?options[mood][]=angry`,
      requestOptions
    )
      .then((response) => response.text())
      // .then((text)=>setImg(text))
      .catch((error) => console.log("error", error));
  }
  return (
    <div className="App">

      {data.map((details) => {
        return (
          <Card
            key={details.id}
            email={details.email}
            name={details.name}
            image={fetchImage(details.username)}
            phone={details.phone}
            website={details.website}
            company={details.company.name}
          />
        );
      })}
    </div>
  );
}

这是我的卡片组件。

    export default function Card(props) {
  return (
    <Box
      w="70vw"
      h="250px"
      borderWidth="1px"
      borderColor={"black"}
      overflow="hidden"
      m="2vh auto"
      display={"flex"}
      flexDir="row"
      color="black"
    >
      <Box>
        <Image
          w="20vw"
          h="250px"
          src={props.image}
          bg="gray"
        />
      </Box>

      <Box display='flex' flexDirection={'column'} alignItems='flex-start' ml='2vw' fontSize={'lg'}>
          <Box fontSize={'3xl'} mb='2vw'>{props.name}</Box>
          <Box><strong>Email: </strong>{props.email}</Box>
          <Box><strong>Phone: </strong>{props.phone}</Box>
          <Box><strong>Company: </strong>{props.company}</Box>
          <Box><strong>Website: </strong>{props.website}</Box>
          <Box><strong>Address: </strong>{props.address}</Box>
      </Box>
    </Box>

我发现返回的是 promise 而不是获取的数据。如果我取消对 setImg promise 的注释,则会连续获取图像但仍不会渲染。请帮忙。提前致谢。

您没有使用 await fetch(...) 结果

一般来说,不要混合使用awaitthen

此外,如果 api returns 图像数据,您不应将其转换为文本,而应将其转换为 blob 并使用 URL.createObjectURL 创建正确的 url

const response = await fetch(
      `https://avatars.dicebear.com/v2/avataaars/${name}.svg?options[mood][]=angry`,
      requestOptions
    )
const blob = await response.blob();
return URL.createObjectURL(blob)

或者如果可以直接使用api url:

return `https://avatars.dicebear.com/v2/avataaars/${name}.svg?options[mood][]=angry`;

但是您应该使用状态来存储生成的 URL。此代码可以在您的 fetchData() 函数中使用,并将 imageUrl 添加到每个项目,以便在每个渲染时不重新提取

App.js:

function App() {
  const [data, setData] = useState("");

  useEffect(() => {
    fetchData(setData);
  }, []);

  return (
    <div className="App">

      {data.map((details) => {
        return (
          <Card
            key={details.id}
            email={details.email}
            name={details.name}
            username={details.username} // <=== Change image prop to username prop
            phone={details.phone}
            website={details.website}
            company={details.company.name}
          />
        );
      })}
    </div>
  );
}

卡片组件:

export default function Card(props) {
  const imgURL = `https://avatars.dicebear.com/v2/avataaars/${props?.name}.svg?options[mood][]=angry`
  return (
    <Box
      w="70vw"
      h="250px"
      borderWidth="1px"
      borderColor={"black"}
      overflow="hidden"
      m="2vh auto"
      display={"flex"}
      flexDir="row"
      color="black"
    >
      <Box>
        <Image
          w="20vw"
          h="250px"
          src={imgURL} //<=== This is src img
          bg="gray"
        />
      </Box>

      <Box display='flex' flexDirection={'column'} alignItems='flex-start' ml='2vw' fontSize={'lg'}>
          <Box fontSize={'3xl'} mb='2vw'>{props.name}</Box>
          <Box><strong>Email: </strong>{props.email}</Box>
          <Box><strong>Phone: </strong>{props.phone}</Box>
          <Box><strong>Company: </strong>{props.company}</Box>
          <Box><strong>Website: </strong>{props.website}</Box>
          <Box><strong>Address: </strong>{props.address}</Box>
      </Box>
    </Box>

问题

问题是 fetchData 函数在渲染 data 数组时被无条件调用。当 .then((text)=>setImg(text)) 取消注释时,它会更新状态并触发重新渲染。重复广告恶心。

function App() {
  const [data, setData] = useState([]);
  const [img, setImg] = useState([]);

  useEffect(() => {
    fetchData(setData);
  }, []);

  async function fetchImage(name) {
    const requestOptions = {
      method: "GET",
      redirect: "follow",
    };
    await fetch(
      `https://avatars.dicebear.com/v2/avataaars/${name}.svg?options[mood][]=angry`,
      requestOptions
    )
      .then((response) => response.text())
      .then((text)=>setImg(text)) // <-- (2) update state, trigger rerender
      .catch((error) => console.log("error", error));
  }

  return (
    <div className="App">
      {data.map((details) => {
        return (
          <Card
            key={details.id}
            email={details.email}
            name={details.name}
            image={fetchImage(details.username)} // <-- (1) immediately invoked!
            phone={details.phone}
            website={details.website}
            company={details.company.name}
          />
        );
      })}
    </div>
  );
}

解决方案

您似乎不需要“获取”图像,您可以简单地使用计算出的图像源值。如果需要,请创建效用函数。

function App() {
  const [data, setData] = useState([]);
  const [img, setImg] = useState([]);

  useEffect(() => {
    fetchData(setData);
  }, []);

  // (1) utility function to compute image source string
  const getImageSrc = name => {
    return `https://avatars.dicebear.com/v2/avataaars/${name}.svg?options[mood][]=angry`
  };

  return (
    <div className="App">
      {data.map((details) => {
        return (
          <Card
            key={details.id}
            email={details.email}
            name={details.name}
            image={getImageSrc(details.name)} // <-- (2) call utility
            phone={details.phone}
            website={details.website}
            company={details.company.name}
          />
        );
      })}
    </div>
  );
}