title: Recursive Function in React.JS Component class
body: <p>I have a problem with a project that uses React. It's a tic tac toe game and I am trying to implement the computer player. </p>
  
  <p>When the human player clicks on one square (Field-component) this triggers
  the <em>updateField()</em> function in the Board-component. It also calls the <em>computerMove()</em> function which in turn calls the <em>minimax()</em> function. </p>
  
  <p>The minimax function is recursivly defined. However, I get the following error message, when the code execution reaches the line where <em>minimax(possibleGame)</em> is called.</p>
  
  <pre><code>[ERROR] react-dom Uncaught TypeError: Cannot read property 'minimax' of undefined
  </code></pre>
  
  <p>Apparently the function is unknown, which I don't understand because I bind it to the Board scope.</p>
  
  <pre><code>class Field extends React.Component{
  
    render(){
      return(
        &lt;button className='field' onClick={this.props.clickFunc}&gt;{this.props.value}&lt;/button&gt;
      );
    }
  }
  
  class Board extends React.Component{
    constructor(){
      super();
      this.state = {
        fields: Array(9).fill(null),
      };
      this.minimax = this.minimax.bind(this);
      this.updateField = this.updateField.bind(this);
      this.computerMove = this.computerMove.bind(this);
    }
  
    updateField(id){
      const fields = this.state.fields.slice();
  
      // only proceed if field hasn't been taken yet
      if (fields[id] == null &amp;&amp; this.props.winner == null){
        fields[id] = this.props.playerSymbol;
        this.setState({fields: fields});
  
        this.computerMove(fields);
      } 
    }
  
  // check if somebody won the game
    checkWinner(squares){
      const lines = [
      [0, 1, 2],
      [3, 4, 5],
      [6, 7, 8],
      [0, 3, 6],
      [1, 4, 7],
      [2, 5, 8],
      [0, 4, 8],
      [2, 4, 6],
    ];
    for (let i = 0; i &lt; lines.length; i++) {
      const [a, b, c] = lines[i];
      if (squares[a] &amp;&amp; squares[a] === squares[b] &amp;&amp; squares[a] === squares[c]) {
        return squares[a];
      }
    }
    return null;
  
    }
  
    computerMove(fields){
      var computerSymbol = (this.props.playerSymbol == "X" ? "O" : "X");
      var game = {fields: fields,turn:computerSymbol};
      var result = this.minimax(game);
      var newBoard = fields.slice();
      newBoard[result[1]] = computerSymbol;
      this.setState({fields: newBoard}); 
  
      }
  
    score(game){
      // check for winner
      var result = this.checkWinner(game.fields);
      if (result !== null){
        if (result == this.props.playerSymbol){
          return -10;
        } else{
          return 10;
        }
      }else{
        return 0;
      }
    }
  
    minimax(game) {
      var score = this.score(game);
      if (score !== 0){
        return score;
      }
      var scores = [];
      var moves = [];
  
      game.fields.forEach(function(value,index,arr){
        if (value==null){
          var newField = arr.slice();
          newField[index] = game.turn;
  
          var nextTurn = (game.turn == "X" ? "O" : "X");
          var possibleGame = {fields: newField,turn:nextTurn};
          var result = this.minimax(possibleGame);
          scores.push(result[0]);
          moves.push(index);
        }
      }); 
      if (game.turn == this.props.playerSymbol){
        var max_ind = scores.indexOf(Math.max(...scores));
        return [scores[max_ind],moves[max_ind]];
      } else{
        var min_ind = scores.indexOf(Math.min(...scores));
        return [scores[min_ind],moves[min_ind]];
      }   
    }
  
    render(){
      var fields = this.state.fields;
  
      // check if somebody won
  
      const winner = this.checkWinner(fields);
      if (winner){
        this.props.declareWinner(winner);
      }
  
  
      return (
        &lt;div className="animated fadeInUp board-container"&gt;
          &lt;div className='row'&gt;
            &lt;Field value={fields[0]} clickFunc={() =&gt; this.updateField(0)} /&gt;
            &lt;Field value={fields[1]} clickFunc={() =&gt; this.updateField(1)}/&gt;
            &lt;Field value={fields[2]} clickFunc={() =&gt; this.updateField(2)}/&gt;
          &lt;/div&gt;
          &lt;div className='row'&gt;
            &lt;Field value={fields[3]} clickFunc={() =&gt; this.updateField(3)} /&gt;
            &lt;Field value={fields[4]} clickFunc={() =&gt; this.updateField(4)}/&gt;
            &lt;Field value={fields[5]} clickFunc={() =&gt; this.updateField(5)}/&gt;
          &lt;/div&gt;
          &lt;div className='row'&gt;
            &lt;Field value={fields[6]} clickFunc={() =&gt; this.updateField(6)}/&gt;
            &lt;Field value={fields[7]} clickFunc={() =&gt; this.updateField(7)}/&gt;
            &lt;Field value={fields[8]} clickFunc={() =&gt; this.updateField(8)}/&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        )
    }
  }
  </code></pre>
  
  <p>The whole code can be tested here:
  <a href="https://codepen.io/miga89/pen/pPqmra" rel="nofollow noreferrer">https://codepen.io/miga89/pen/pPqmra</a></p>
  
  <p>I also tried to come up with a MWE (<a href="https://codepen.io/miga89/pen/XRQBjP" rel="nofollow noreferrer">https://codepen.io/miga89/pen/XRQBjP</a>) However, this example works for some reason.</p>
  
  <p>Thank you for your help!</p>