简体   繁体   English

React 自定义图像组件不会根据给定条件呈现

[英]React custom Image Component doesn't render based on given condition

I am trying to build an image component in ReactJS with a fallback prop if provided will render the fallback component until the image has been downloaded and rendered properly.我正在尝试在 ReactJS 中构建一个带有fallback道具的图像组件,如果提供了将呈现后备组件,直到图像被下载并正确呈现。

The conditional rendering is as follows:条件渲染如下:

if (loading) {
    return fallback;
  } else if (error) {
    return <span>ERROR</span>;
  } else if (src) {
    return (
      <>
        <img alt="" ref={imageRef} decoding="async" src={props.src} />
      </>
    );
  } else return null;
}

And the Image is called in the App.js file as并且图像在 App.js 文件中被称为

<Image
  src="https://source.unsplash.com/random/100x100"
  fallback={<h1>Loading...</h1>}
/>

I'm using useEffect hook to call function that further checks if the image has been mounted to the screen using ref .我正在使用useEffect挂钩调用 function 进一步检查图像是否已使用ref安装到屏幕上。

React.useLayoutEffect(() => {
    imageRef.current = true;
    start();
    return () => {
      imageRef.current = false;
    };
  }, []);

  async function start() {
    if (!src || !fallback) {
      const errorMessage = "`src` & `fallback` must be provided";
      setError(errorMessage);
      return;
    }
    setLoading(true);
    tryLoadImage();
  }

  async function loadImage() {
    const img = imageRef.current;
    if (!img) {
      return;
    }

    setLoading(false);
  }

  async function tryLoadImage() {
    try {
      await loadImage();
      if (imageRef.current) {
        setLoading(false);
      }
    } catch (error) {
      console.log("error", error);
    }
  }

The problem I'm facing:我面临的问题:

  1. Even after using conditional statements in the return part, the component gives a black-white space then renders the image, hence no such 'Loading...' is getting rendered on the screen.即使在return部分使用条件语句后,组件也会给出一个黑白空间然后渲染图像,因此屏幕上不会渲染这样的“正在加载...”。
  2. I have tried using setTimeOut for the delay in 'setLoading' prop, in this case, the fallback is getting rendered after that certain timeout delay not before.我已经尝试使用 setTimeOut 来延迟“setLoading”道具,在这种情况下,回退是在某个超时延迟之后而不是之前呈现的。

Things I'm unsure about:我不确定的事情:

  1. Is this happening due to batch update in the useState hook?这是由于 useState 挂钩中的批量更新而发生的吗?
  2. My useEffect hook fires after the return gets painted to the screen.我的 useEffect 钩子在返回被绘制到屏幕后触发。 Is this mechanism correct in my usecase?这种机制在我的用例中是否正确?

Kindly refer to Codesandbox link for the live demo/code: https://codesandbox.io/s/img-lazy-ke6zz现场演示/代码请参考 Codesandbox 链接: https://codesandbox.io/s/img-lazy-ke6zz

Any help in the right direction would be quite helpful.任何朝着正确方向的帮助都会非常有帮助。

You can use useEffect better in this case;在这种情况下,您可以更好地使用useEffect you have a state loading .你有一个 state loading You should listen to when this value changes in your useEffect .你应该听听你的useEffect中这个值何时发生变化。

useEffect(() => {
  setLoading(false);
}, [loading]);

The value you pass in the array in the useEffect hook is getting listened to (there can be more than value in here, as it's an array).您在 useEffect 钩子中传递给数组的值会被监听(这里可能不止值,因为它是一个数组)。 So when one of those values changes you run the code in useEffect.因此,当其中一个值发生更改时,您可以在 useEffect 中运行代码。 In this component loading should only changes once to false.在这个组件中, loading应该只更改一次为 false。 So whenever you use setLoading in your code this useEffect is ran.因此,每当您在代码中使用setLoading时,都会运行此 useEffect。

I recommend you read more about this hook here: https://reactjs.org/docs/hooks-effect.html我建议您在此处阅读有关此钩子的更多信息: https://reactjs.org/docs/hooks-effect.html

Also, I think it's better in this case, you default the loading state to true instead of false.另外,我认为在这种情况下更好,您默认loading state 为 true 而不是 false。 So when the component renders it is loading from the start.因此,当组件呈现时,它会从头开始加载。 In the start function you can use setLoading to false when src or fallback isn't set.start function 中,当 src 或 fallback 未设置时,您可以使用setLoading为 false。 This is also why your fallback isn't being shown.这也是为什么您的后备没有显示的原因。 As you default loading to false and you show the fallback when this is loading is true.当您默认loading为 false 时,您会在loading为 true 时显示回退。

A better practice of using React.useEffect and React.useState is importing it in your file.使用React.useEffectReact.useState的更好做法是将其导入文件中。 This can be done as followed import React, { useRef, useEffect, useState } from "react";这可以按照以下方式完成import React, { useRef, useEffect, useState } from "react"; . . Then you can use them like this const [loading, setLoading] = useState(false);然后你可以像这样使用它们const [loading, setLoading] = useState(false); without React prefixing it.没有 React 前缀。

You can find an edited version of your CodeSandbox here https://codesandbox.io/s/img-lazy-forked-l8zuf?file=/src/Image.js .您可以在https://codesandbox.io/s/img-lazy-forked-l8zuf?file=/src/Image.js找到 CodeSandbox 的编辑版本。 I also changed the returning statement, which you can do if you don't want to show errors.我还更改了返回语句,如果您不想显示错误,可以这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM