下面的代码片段清楚地说明了这些问题。 如果您通过单击按钮运行代码片段,则会出现说明
触发问题的代码是
[0,1].map((i) => <Star src={this.state.src[i]} changeIcon={this.changeIcon} key={i} id={i} />)
{this.state.src[i]}
不会在jsx
更新时触发state
的重新渲染
const host = 'https://s3.eu-central-1.amazonaws.com/moviedatabase1/'
const noStarIcon = host + 'no_star.png'
const StarIcon = host + 'star.png'
class Feedback extends React.Component {
constructor(props){
super(props);
this.state = { src: [noStarIcon, noStarIcon, noStarIcon], text: "" }
this.changeIcon = this.changeIcon.bind(this)
this.list = [0,1].map((i) => <Star src={this.state.src[i]} changeIcon={this.changeIcon} key={i} id={i} />)
}
changeIcon(){
this.setState({text: this.state.text + " state updated!"})
this.setState({src: [StarIcon, StarIcon, StarIcon]})
}
render() {
return (
<React.Fragment>
<p id="console">{this.state.text}</p>
<div class="box">{this.list}</div>
<div class="box box-blue flex-box">
<p>If I use the normal <b>jsx</b> tag, <b>setState</b> will trigger re-rendering of the <b>jsx</b> element</p> and the star will become yellow!
</div>
<div class="box">
<Star changeIcon={this.changeIcon} src={this.state.src[2]} key={2} id={2}/>
</div>
</React.Fragment>
);
}
}
class Star extends React.Component {
render() {
return <img src={this.props.src} onClick={this.props.changeIcon} style={this.props.style} id={this.props.id} />;
}
}
ReactDOM.render(
<Feedback />,
document.getElementById("react")
);
.box {
margin: 2vh 2vw;
color: white;
}
.box-blue {
border: solid 2px red;
background-color: blue;
border: solid 1px red;
margin: 2vh 2vw;
padding: 2vh 2vw;
color: white;
}
.flex-box {
display: flex;
flex-direction: column;
justify-content: space-around;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div class="box box-blue flex-box">
<p>The two stars below are multiple <b>Components</b> rendered using the Javascript <b>.map</b> function, which saves an array of two <b>Star</b> components.</p>
<p>If you click on this two stars, the function <b>changeIcon</b> is called and updates the <b>state</b>, but the <b>jsx</b> is not re-rendered</p>
</div>
<div id="react"></div>
<hr>
<p>Credits for the icons</p>
<div>Icons made by <a href="https://www.flaticon.com/authors/smashicons" title="Smashicons">Smashicons</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> is licensed by <a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a></div>
答案 0 :(得分:1)
这是因为要在构造函数中设置this.list
。调用this.setState
不会再次调用您的构造函数,因此不会对其进行更新。它仅触发生命周期事件(例如render
)。见下文。
const host = 'https://s3.eu-central-1.amazonaws.com/moviedatabase1/'
const noStarIcon = host + 'no_star.png'
const StarIcon = host + 'star.png'
class Feedback extends React.Component {
constructor(props){
super(props);
this.state = { src: [noStarIcon, noStarIcon, noStarIcon], text: "" }
this.changeIcon = this.changeIcon.bind(this)
}
changeIcon(){
this.setState({text: this.state.text + " state updated!"})
this.setState({src: [StarIcon, StarIcon, StarIcon]})
}
render() {
return (
<React.Fragment>
<p id="console">{this.state.text}</p>
<div class="box">{[0,1].map((i) => <Star src={this.state.src[i]} changeIcon={this.changeIcon} key={i} id={i} />) }</div>
<div class="box box-blue flex-box">
<p>If I use the normal <b>jsx</b> tag, <b>setState</b> will trigger re-rendering of the <b>jsx</b> element</p> and the star will become yellow!
</div>
<div class="box">
<Star changeIcon={this.changeIcon} src={this.state.src[2]} key={2} id={2}/>
</div>
</React.Fragment>
);
}
}
class Star extends React.Component {
render() {
return <img src={this.props.src} onClick={this.props.changeIcon} style={this.props.style} id={this.props.id} />;
}
}
ReactDOM.render(
<Feedback />,
document.getElementById("react")
);
.box {
margin: 2vh 2vw;
color: white;
}
.box-blue {
border: solid 2px red;
background-color: blue;
border: solid 1px red;
margin: 2vh 2vw;
padding: 2vh 2vw;
color: white;
}
.flex-box {
display: flex;
flex-direction: column;
justify-content: space-around;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div class="box box-blue flex-box">
<p>The two stars below are multiple <b>Components</b> rendered using the Javascript <b>.map</b> function, which saves an array of two <b>Star</b> components.</p>
<p>If you click on this two stars, the function <b>changeIcon</b> is called and updates the <b>state</b>, but the <b>jsx</b> is not re-rendered</p>
</div>
<div id="react"></div>
<hr>
<p>Credits for the icons</p>
<div>Icons made by <a href="https://www.flaticon.com/authors/smashicons" title="Smashicons">Smashicons</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> is licensed by <a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a></div>