0

The problem i have is that React does not update in the situation below.
I added a forceUpdate() when the component should update just to make extra sure.

The code is simple so there is not much to say.
It's as if React does not see that it should update or am i doing something really wrong here?

class Greetings extends React.Component{
  constructor(props){
    super(props)
    this.switchLanguage = this.switchLanguage.bind(this)
    this.state = {
      languageID: 0,
    }
    
    this.arrayContainingRenderValues = [
        <span>{this.props.greetingArray[this.state.languageID]}!</span>,
        <span>No greetings for you!!</span>
      
    ]
  }
  
  switchLanguage(){
    this.setState((previousState) => ({languageID: (previousState.languageID + 1) % this.props.greetingArray.length}))
    
    
    this.forceUpdate()
  }
  
  componentDidMount(){
    this.timerID = setInterval(this.switchLanguage, 500)
  }
  componentWillDismount(){
    clearInterval(this.timerID)
  }
  
  render(){
    return this.arrayContainingRenderValues[0]

    //The return below works without problem
    return <span>{this.props.greetingArray[this.state.languageID]}!</span>
  }
}


let content = <Greetings greetingArray={["Good morning","Bonjour","Buenos días","Guten tag","Bom dia","Buongiorno"]}/>

ReactDOM.render(content, document.getElementById('root'))

Ah this code is an example and I don't really need it to work but it would be nice if it did. Thanks.

  • I see you edited your question to remove the console log after the state update. I copied this code into a codesandbox and it seems to cycle through the passed `greetingArray` prop array on the 500ms interval (though I did comment out the first return since it didn't seem valid because of the second return). What exactly is the issue? – Drew Reese Mar 19 '21 at 21:21
  • Thanks for answering, i just had a problem understanding why it did not update. I moved the array from the `constructor()` to the `render()` and it works. Sorry, i am just trying out React to see how it works and i expected that code to just work. – D Guerchôm Mar 19 '21 at 21:41
  • When you define `this.arrayContainingRenderValues` in the constructor you enclosed the current/initial `this.state.languageID` value, so no amount of updating the `this.state.languageID` later will update this stale enclosure. You would want to recompute `this.arrayContainingRenderValues` value every time state updates. When you move the array to render you are recomputing each time. Where you trying to apply some conditional rendering in case the `this.props.greetingArray` is empty? – Drew Reese Mar 19 '21 at 21:48

1 Answers1

0

Issue

When you define this.arrayContainingRenderValues in the constructor you enclosed the current/initial this.state.languageID value, so no amount of updating the this.state.languageID later will update this stale enclosure. You would want to recompute this.arrayContainingRenderValues value every time state updates. When you move the array to render you are recomputing each time.

Solution

It looks like you are attempting to apply some conditional rendering if this.props.greetingArray is empty (or not passed).

class Greetings extends React.Component {
  constructor(props) {
    super(props);
    this.switchLanguage = this.switchLanguage.bind(this);
    this.state = {
      languageID: 0
    };
  }

  switchLanguage() {
    this.setState((previousState) => ({
      languageID:
        (previousState.languageID + 1) % this.props.greetingArray.length
    }));
  }

  componentDidMount() {
    this.timerID = setInterval(this.switchLanguage, 500);
  }
  componentWillDismount() {
    clearInterval(this.timerID);
  }

  render() {
    return this.props.greetingArray.length ? (
      <span>{this.props.greetingArray[this.state.languageID]}!</span>
    ) : (
      <span>No greetings for you!!</span>
    );
  }
}

Demo

Edit react-does-not-see-that-the-markup-changes-when-content-is-nested-in-array

Drew Reese
  • 165,259
  • 14
  • 153
  • 181
  • A okay thank you I get it now. When assigning the values to `this.renderValues[]` they get evaluated and then they are fixed, I did not understand that to get updated they had to be reassigned somewhere in the `render()`. But since the whole array has to be recomputed every time then it would be an inefficient way to do things if for some reason I had lots of values inside it. – D Guerchôm Mar 20 '21 at 07:27
  • @DGuerchôm If I understand this previous comment, I don't think it'd be that computationally complex since you aren't recomputing an entire source array, but rather just selecting a single greeting text from it by index. Your code was only inefficient because it was storing extra derived state from the passed props versus rendering directly from props. – Drew Reese Mar 23 '21 at 15:40