0

Very simple. I am making a button to change the state of my parent based on what is entered into an input bar. After the user types a code in and clicks enter a for loop is called which iterates through an array to make sure that the code the user entered is present in the array. If the code is present, this.setState is called and the parent's state is changed.

However, after passing the function from the parent to the button component, if I even type in a string that is in the array into the input field I automatically get an Error: Maximum update depth exceeded saying that the component is repeatedly calling setState -- however, that shouldn't even be possible since I have yet to click the button so the for loop shouldn't even be in use. (well it might be possible I have no clue why it is doing that)

This is the parent:

constructor(props){
    super(props);

    this.state = {
      roomList: [],
      activeRoom: undefined
    };

    this.onUpdateRooms = this.onUpdateRooms.bind(this);
  }

//function for changing state
  onJoinRoom(roomCode) {
    for(let i = 0; i < this.state.roomList.length; i++){
      if (this.state.roomList[i].roomCode === roomCode) {
        this.setState({activeRoom: roomCode});
        console.log('Found')
      }
    }
  }

//within the render
<JoinButton onJoinRoom={this.onJoinRoom}/>

This is my button class:

constructor (props) {
        super(props)
        this.state = {
          enteredCode: ''
        }
      }

    handleInput(e) {
        this.setState({enteredCode: e.target.value});
    }

    handleClick() {
        this.props.onJoinRoom(this.state.enteredCode);
    }

    render() {
        return (
            <div>
                <input 
                    className="roomCodeInput"
                    type='text'
                    placeholder='Enter A Room Code'
                    onChange={this.handleInput.bind(this)}
                    value={this.state.enteredCode} 
                />
                <button className="join" onClick={this.handleClick(this)}>JOIN</button>
            </div>
        );
    }

I did a bit of research and people say that one reason for this error is for calling the function within the render method(ie. onClick={this.props.function()} instead of .function without the parenthesis). However, I am using handleClick and binding it so I don't believe my problem is the same. In addition, I need to pass the function parameters so the parenthesis are necessary.

Really confused right now, would love some help :/

ZKJ
  • 167
  • 4
  • 15
  • 1
    `onClick={()=>this.handleClick(this)}` – ludwiguer Jul 02 '20 at 02:27
  • Although I don’t know why are you passing `this` since you have access to it globally and you’re not using it anywhere in the function – ludwiguer Jul 02 '20 at 02:29
  • Ah I assumed that is just how you bind things... I was referencing another project's syntax and they were doing it too xD. – ZKJ Jul 02 '20 at 02:35

2 Answers2

1

First thing you need to do is bind your functions to the corresponding components in the constructors because when you do things like set state or use events. React doesn't know what context to do these things on.

this.onJoinRoom = this.onJoinRoom.bind(this); will bind the function to the parent class.

And you'll need to do the same with button class

this.handleClick = this.handleClick.bind(this);
this.handleInput = this.handleInput.bind(this);

And then simply call the functions defined in the constructors; without brackets.

<div>
    <input 
        className="roomCodeInput"
        type='text'
        placeholder='Enter A Room Code' 
        onChange={this.handleInput}
        value={this.state.enteredCode} 
    />
    <button className="join" onClick={this.handleClick}>JOIN</button>
</div>
Tony
  • 436
  • 1
  • 9
  • 17
1

I think it might be because you are trying to bind this while passing function to onChange event.
Instead of that, I suggest you use arrow functions, so you need not worry about binding to this.
Just change your handleInput function as below

handleInput = (e) => {
      this.setState({enteredCode: e.target.value});
    }

And then you can simply pass handleInput to your event handler like this

 <input 
     className="roomCodeInput"
     type='text'
     placeholder='Enter A Room Code'
     onChange={this.handleInput}  //need not bind this
     value={this.state.enteredCode} 
     />

Also inside your parent, you haven't bind this to onJoinRoom handler so you need to convert it to arrow function or you can bind to this inside constructor.
See this question for difference between the arrow and normal function-
Are 'Arrow Functions' and 'Functions' equivalent / exchangeable?

Sagar Darekar
  • 982
  • 9
  • 14
  • I did bind this to onJoinRoom in my parent I just accidetally deleted it in my post(I meant to delete the current bind that is shown because it was unrelated). Thank you for your answer, it is very well explained. If I could accept 2 I would :( – ZKJ Jul 02 '20 at 03:21