Ramen_Lover912
Ramen_Lover912

Reputation: 57

I can't type in input

import React, { Component, createElement } from "react";

export default class TodoList extends Component {
  handleKeyDown = (e) => {
    if (e.keyCode === 13) {
      console.log("enter has been pressed");
    }
  };

  handleChange = (e) => {
    console.log("something has occurred");
  };

  render() {
    return (
      <div className="container">
        <h1 className="heading">Todo List</h1>
        <div className="list">No todos.</div>
        <input
          type="text"
          className="insertTodo"
          placeholder="Add a new todo!"
          onChange={this.handleChange}
          onKeyDown={this.handleKeyDown}
          value={this.state.inputValue}
        />
      </div>
    );
  }
}

I can't seem to type into the input which is why handleChange isn't getting called. Am I doing something wrong? handleKeyDown is working fine, logging to the console when the enter key is pressed.

Thanks!

Upvotes: 0

Views: 47

Answers (3)

Samathingamajig
Samathingamajig

Reputation: 13245

  1. Your syntax for writing functions is wrong. In classes, you don't say func = (e) => {...}, you say func(e) {...}
  2. You need to bind the this context to each class function
  3. In your original code, you used e.preventDefault() which prevented handleChange() from being called
  4. React doesn't do 2-way binding, like Svelte does, so you need to set state manually.

https://jsfiddle.net/4vs685u1/1/

class TodoList extends React.Component {
    constructor(props) {
    super(props);
    this.state = {
        inputValue: ""
    }
    this.handleKeyDown = this.handleKeyDown.bind(this);
    this.handleChange = this.handleChange.bind(this);
  }

  handleKeyDown(e) {
    if (e.keyCode === 13) {
      console.log("enter has been pressed");
    }
  }

  handleChange(e) {
    console.log("something has occurred");
    this.setState({
        inputValue: e.target.value
    })
  }

  render() {
    return (
      <div className="container">
        <h1 className="heading">Todo List</h1>
        <div className="list">No todos.</div>
        <input
          type="text"
          className="insertTodo"
          placeholder="Add a new todo!"
          onChange={this.handleChange}
          onKeyDown={this.handleKeyDown}
          value={this.state.inputValue}
        />
      </div>
    );
  }
}

ReactDOM.render(<TodoList />, document.querySelector("#root"));
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<div id="root"></div>

If you're just now learning React, I would recommend using Functional Components with Hooks. The syntax is a lot more straight forward:

const TodoList = () => {
  const [inputValue, setInputValue] = React.useState("");
  
  const handleKeyDown = (e) => {
    if (e.keyCode === 13) {
      console.log("enter has been pressed");
    }
  }
 
  const handleChange = (e) => {
    console.log("something has occurred");
    setInputValue(e.target.value);
  } 
  
  return (
      <div className="container">
        <h1 className="heading">Todo List</h1>
        <div className="list">No todos.</div>
        <input
          type="text"
          className="insertTodo"
          placeholder="Add a new todo!"
          onChange={handleChange}
          onKeyDown={handleKeyDown}
          value={inputValue}
        />
      </div>
    );
}

ReactDOM.render(<TodoList />, document.querySelector("#root"));
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<div id="root"></div>

Upvotes: 1

Kerosz
Kerosz

Reputation: 168

I to give an answer to clarify some of the things that were raised in the comments which are related to the way you functions work.

Now first of all you cannot type into the input because you are using controlled inputs and you do not set the state of your input, therefor your input value will always be the value you set as default in the state.

  constructor(props) {
    super(props);
    this.state = { inputValue: "" };
  }

So all you have to do is set the state when the input changes

  handleChange = (e) => {
    this.setState({ ...this.state, inputValue: e.target.value })
    console.log("something has occurred");
  };

The second thing that was mentioned in comments is that you do not use proper syntax for functions, and that was a reference that in class components you usually have to bind the this keyword to the class itself. In your case however because you are using arrow functions, the this keyword is set the the lexical scope of where the function was defined there for this is already set to the class itself. So there is no need to bind it.

Upvotes: 1

Bruno Monteiro
Bruno Monteiro

Reputation: 4519

You need to bind your methods. From the docs:

If you forget to bind this.handleClick and pass it to onClick, this will be undefined when the function is actually called.

import React, { Component, createElement } from "react";

export default class TodoList extends Component {
  constructor(props){
    this.handleKeyDown = this.handleKeyDown.bind(this)
    this.handleChange = this.handleChange.bind(this)
  }

  // The rest of your component code here...

  }
}

Also, using arrow functions like you're doing is "experimental syntax" in React. You should consider either using function components or changing you function declaration to a non arrow function:

handleChange(e) => {
  console.log("something has occurred");
};

More info: https://reactjs.org/docs/handling-events.html

Upvotes: 1

Related Questions