在事件侦听器之后反应组件渲染

React component render after event listener

我在获取组件生命周期以与 React 中的事件侦听器协作时遇到了一些问题。下面是一个示例应用程序,它显示来自用户提供的 URL 的图像,并使用图像的宽度来应用样式——在这种情况下,我希望图像以 1/2 的比例显示,所以我得到了宽度图像的宽度,然后将其宽度设为实际宽度的 1/2。

为此,我在 render() 方法中使用图像的 naturalWidth 作为 属性。我在 componentDidMount() 方法中创建了一个图像实例,然后使用事件侦听器等待图像加载完毕以获取其宽度。如果没有事件侦听器,它将尝试在加载图像之前获取宽度并且不会 return 一个值,因此侦听器确保在我们获取宽度之前加载图像。这就是我 运行 遇到问题的地方:render() 方法不受事件侦听器的限制,因此即使 之前触发了 componentDidMount() render(),它始终以初始状态呈现。我希望通过更改状态作为事件的一部分,组件将重新呈现,但事实并非如此。

确保在事件侦听器完成获取图像宽度值后呈现内容的“正确”方法是什么?

import React, {Component,} from 'react'
import './app.css'

class App extends Component {

// setting the initial state with a placeholder image
state = {
    src: "https://cdn.jpegmini.com/user/images/slider_puffin_jpegmini_mobile.jpg",
    width: "",
}

// Getting the width of the image when the component mounts
componentDidMount() {
    let Img = document.createElement("img");
    Img.src = this.state.src
    Img.addEventListener("load", () => {
        this.state.width = Img.naturalWidth
    });
}

//re-calculating the width when the image changes (exact same as above)
componentDidUpdate() {
    let Img = document.createElement("img");
    Img.src = this.state.src
    Img.addEventListener("load", () => {
        this.state.width = Img.naturalWidth
    });
}

// This function updates the state when the input is changed
change = (e) => {
    this.setState({
  [e.target.name]: e.target.value
    })
};

render() {

    return (
        <div className="app">
                <input
                    name="src"
                    value={this.state.src}
                    onChange={e => this.change(e)}
                    disabled={false}
                    ></input>
                <img
                    src={this.state.src}
                    style={{width: this.state.width / 2}}
                    ></img>
            </div>
    )

}
}

export default App

您可以有条件地渲染图像,并且仅在 this.state.width 包含一个值时才显示它。

此外,您应该使用 setState,而不是改变现有状态(这不是 React 的处理方式,不会导致状态更新)。

与其重复两次图像宽度计算,不如将其放入一个函数中并调用该函数两次。尽可能 remember to use const 而不是 let

calcImageWidth() {
    const img = document.createElement("img");
    img.src = this.state.src
    img.addEventListener("load", () => {
        // use this technique in componentDidUpdate too
        this.setState(prevState => ({ ...prevState, width: img.naturalWidth }));
    });
}
componentDidMount() {
  this.calcImageWidth();
}
componentDidUpdate() {
  this.calcImageWidth();
}
render() {
    return (
        <div className="app">
            <input
                name="src"
                value={this.state.src}
                onChange={e => this.change(e)}
                disabled={false}
            ></input>
            {
                this.state.width === ''
                    ? null
                    : <img
                          src={this.state.src}
                          style={{ width: this.state.width / 2 }}
                      ></img>
            }
        </div>
    );
}