问题描述
我在获取组件生命周期以与React中的事件侦听器配合方面遇到一些麻烦。下面是一个示例应用程序,该应用程序显示用户提供的URL中的图像,并使用图像的宽度来应用样式-在这种情况下,我希望图像以1/2比例显示,这样我就可以得到图像的宽度和然后将其宽度设置为实际宽度的1/2。
为此,我将图像的naturalWidth
用作render()
方法中的属性。我在componentDidMount()方法中创建图像的实例,然后使用事件侦听器等待图像加载完成以获取其宽度。如果没有事件侦听器,它将尝试在加载图像之前获取宽度,并且不会返回任何值,因此侦听器将确保在获取宽度之前加载图像。那就是我遇到的一个问题:render()
方法不受事件监听器的限制,因此即使在{em>之前 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>
);
}