0

Hi Trying to learn React right now, still making just baby steps. I wrote code bellow in codepen(see link on the bottom), in my code I put a few log to console statements I can't figure out why my function handleSubmit which is inside upmost component('TodoApp') cannot access state?

I figured it cannot access it because I can print to console text just above 'let current_todos = this.state.todos' but I never see in console text just bellow it.

If this is incorrect how am I supposed to access state then? NOTE: I realize that a lot of code in that function is redundant but I declare these variables and log statements for debugging purposes

class TodoApp extends React.Component {
  constructor(props) {
    super(props)
    this.state = { 
      todos : [ ] 
    }
  }
  render() {
    return (
      <div className='todo-comp todo-app'>
        <h2>ToDo App</h2>
        <form onSubmit={this.handleSubmit}>
          <input type="text">
          </input>
        </form>
        <TodoList todos={this.state.todos}/>
       </div>
    )
  }
  handleSubmit(event) {
    let new_todo = event.target.children[0].value
    console.log("Submited: ".concat(new_todo))
    let current_todos = this.state.todos
    console.log("Succesfully accessed state")
    this.setState({"todos" : this.state.todos.push(new_todo)})
  }
}

class TodoList extends React.Component {
  constructor(props) {
    super(props)
  }
  render () {
    return (
      <ul className="todo-comp todo-list">
      {this.props.todos.map(
          function(item,key) {
            return(
              <li key={key} className="todo-comp todo-item">{item}</li>
            )
      })}
    </ul>
    )
  }
}

ReactDOM.render(
  <TodoApp />,
  document.getElementById('app'),
  console.log("App has been rendered"))

My CodePen Link

sgp667
  • 1,797
  • 2
  • 20
  • 38

2 Answers2

1

When calling this.handleSubmit, you should add .bind(this), since the context is different on invocation time. Another option would be to add the following line in the constructor:

this.handleSubmit = this.handleSubmit.bind(this)
Daniel Stoyanoff
  • 1,443
  • 1
  • 9
  • 25
  • 1
    On top of this, if you write a function as an arrow function, it will be treated as having the binding by default: handleSubmit = (event) => { .... } – mikeg542 Jun 04 '18 at 14:49
  • wow I knew it was something simple, you also made me understand why I always see those binds in constructor. So in other words my function was looking for 'this' in wrong environment? – sgp667 Jun 04 '18 at 14:49
  • Using an arrow function in render method is not recommended by TSLint so I personally avoid it. And yes, you were bound to the wrong this, which has no "state" property. – Daniel Stoyanoff Jun 04 '18 at 14:55
1

The first mistake is that your handleSubmit will be recreated on every render.

This code will allow you to see the input value and submit etc. Hope this helps, if you have anymore questions just comment underneath.

class TodoApp extends React.Component {
  constructor(props) {
    super(props)
    this.handleSubmit = this.handleSubmit.bind(this)
    this.onChange= this.onChange.bind(this)
    this.state = { 
      todos : [ ] 
    }
  }

  onChange(event) {
    this.setState({ text: e.target.value })
  }

  handleSubmit(event) {
    const { text } = this.state;
    // Your submit value;
    console.log(text)
  }
  render() {
    return (
      <div className='todo-comp todo-app'>
        <h2>ToDo App</h2>
        <form onSubmit={this.handleSubmit}>
          <input type="text" onChange={this.onChange}>
          </input>
        </form>
        <TodoList todos={this.state.todos}/>
       </div>
    )
  }
}
jovi De Croock
  • 595
  • 2
  • 8