状态更改时未重新列出列表jsx

时间:2018-12-14 15:42:31

标签: reactjs

下面的代码片段清楚地说明了这些问题。 如果您通过单击按钮运行代码片段,则会出现说明

run code snippet

触发问题的代码是

[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>

1 个答案:

答案 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>