【问题标题】:Adding a loader to react component添加加载器以响应组件
【发布时间】:2026-02-16 20:20:08
【问题描述】:

我正在尝试为我的 react 组件实现一个加载器,当加载背景图像时它应该显示“正在加载”,然后一旦加载它应该显示“加载”

我的componentwillMount() 上有一个setTimeout(),用于测试加载程序是否按预期运行

我很难理解它如何知道图像何时加载并更改加载状态

是否最好将图像与加载器一起放入单独的组件中,而不是将其放在 Hello 组件中?

https://www.webpackbin.com/bins/-KsOEkf9ubvR6iz4bMxG

更新

我已经设法使用附加到图像的onload() 方法让一个简单的图像加载器工作 - https://www.webpackbin.com/bins/-KsNpZPzveUoby1yriFo

Hello.js

 import React from 'react'
import Loader from './Loader'
import styled from 'styled-components'

const Card = styled.div`
  height: 400px;
  width:20%;
  background: url('https://www.planwallpaper.com/static/images/Light-Wood-Background-Wallpaper.jpg');
`
export default class Test extends React.Component {
  constructor() {
    super()
    this.state = { loading:true}
  }

  componentWillMount()
  {
     setTimeout(() => this.setState({loading: false}), 3000)
      console.log("componentDidMount");
  }

  render() {
    return (
      <div>
        <Card>
        <Loader loading={this.state.loading} />
        </Card>
      </div>
    )
  }
}

Loader.js

import React, { Component } from 'react'
import styled, { keyframes } from 'styled-components'
import { string } from 'prop-types'

const transition1 = keyframes`
  0%     { background: #F19939; }
  33.33% { background: #F8CA8F; }
  66.66% { background: #FBD8AE; }
  100%   { background: #F19939; }
`

const transition2 = keyframes`
  0%     { background: #FBD8AE; }
  33.33% { background: #F19939; }
  66.66% { background: #F8CA8F; }
  100%   { background: #FBD8AE; }
`

const transition3 = keyframes`
  0%     { background: #F8CA8F; }
  33.33% { background: #FBD8AE; }
  66.66% { background: #F19939; }
  100%   { background: #F8CA8F; }
`

const Box = styled.span`
  height: 12px;
  width: 12px;
  margin: 0 3px 0 3px;
  border-radius: 4px;
  animation: 0.4s ${transition1 } infinite;
`

const Box2 = styled(Box)`
  animation: 0.4s ${transition2 } infinite;
`

const Box3 = styled(Box)`
  animation: 0.4s ${transition3 } infinite;
`

const TextWrap = styled.div`
  display: flex;
  flex: 0 0 100%;
  justify-content: center;
  color: #fff;
`

const Para = styled.p`
  color: #fff
  padding: 19px 0 0 0;
`

const ParaLoaded = styled(Para)`
  color: #fff;
  padding: 22px 0 0 0;
`

export default class Loader extends Component {

  render() {
    return (
      <div >
        <div >

          <TextWrap>
            {
              this.props.loading
                ?
                  <Para>Loading...</Para>
                :
                  <ParaLoaded>Loaded</ParaLoaded>
            }
          </TextWrap>

        </div>
      </div>
    )
  }
}

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    你可以这样做:https://www.webpackbin.com/bins/-KsOJpBVfpazfXghJAaF

    LoadBackgroundImage.js

    const LoadBackgroundImage = (component, imageUrl, seconds, success, failure) => {
      let timeoutOccured = false;
      const image = new Image();
      const timeout = setTimeout(() => {
        timeoutOccured = true;
        failure();
      }, seconds * 1000);
    
      image.onload = () => {
        clearTimeout(timeout);
        component.style.backgroundImage = `url('${imageUrl}')`;
        if (!timeoutOccured) success();
      };
      image.src = imageUrl;
    };
    
    export default LoadBackgroundImage;
    

    Hello.js

    import React from 'react'
    import Loader from './Loader'
    import styled from 'styled-components'
    import LoadBackgroundImage from './LoadBackgroundImage'
    
    const Card = styled.div`
      height: 400px;
      width:20%;
    `
    export default class Hello extends React.Component {
      constructor() {
        super()
        this.state = { loading:true}
      }
    
      componentDidMount() {
        LoadBackgroundImage(
          this.card,
          'https://www.planwallpaper.com/static/images/Light-Wood-Background-Wallpaper.jpg',
          5,
          () => this.setState({ loading: false }),
          () => console.log('The image did not load in 5 seconds')
        );
      }
    
      render() {
        return (
          <div>
            <Card innerRef={card => this.card = card}>
              <Loader loading={this.state.loading} />
            </Card>
          </div>
        )
      }
    }
    

    在 render() 中,您使用 innerRef 获取对卡片组件的引用并将其保存在 this.card 中。然后在 componentDidMount 中,您使用此引用和 LoadBackgroundImage 函数来加载图像并在加载时进行监控。如果图像在给定的秒数内加载成功回调将被调用,否则将调用失败回调。 5秒后图片仍然可以加载,但不会调用成功回调。如果你想被调用,你可以跳过这个 ckeck: if (!timeoutOccured) in LoadBackgroundImage 函数。

    【讨论】:

    • 这看起来不错,你也可以用它来检查组件是否正在加载吗?
    • @tomharrison,我不确定当您直接使用background: url(...) 设置背景图像时是否有办法检查背景图像是否正在加载。可能不会。