N.O
N.O

Reputation: 53

Input field not erasing React

I'm learning React and I created a simple todo list app and I'm trying to erase the input field as I did for my onClick function on my keypress function. However, it doesn't render the same when I use setTodoInput(""); on that keypress function. It only shows the first character of the input. If I comment out setTodoInput(""); out of the keypress function, it works fine, but the input field doesn't erase. I don't understand why although I have a controlled input, it doesn't function the same. if someone can please explain, it would be appreciated.

this is my code for my App file:

import React, { useState } from "react";
import InputArea from "./InputArea";
import ToDoTask from "./ToDoTask";

function App() {
  const [todoTasks, setTodoTasks] = useState([]);

  function addTask(todoInput) {
    setTodoTasks((prevTodoTasks) => {
      return [...prevTodoTasks, todoInput];
    });
  }

  function handleKeyPress(event) {
    if (event.key === "Enter") {
      setTodoTasks((prevTodoInput) => {
        const newTodoInput = event.target.value;
        return [...prevTodoInput, newTodoInput];
      });
      // const newTodoInput = event.target.value;
      //   setTodoTasks((prevTodoTasks) => {
      //     console.log(newTodoInput);
      //     return [...prevTodoTasks, newTodoInput];
      //   });
      // }
    }
  }

  function deleteTodoTask(id) {
    setTodoTasks((prevTodoTasks) => {
      return prevTodoTasks.filter((task, i) => {
        return i !== id;
      });
    });
  }

  return (
    <div className="container">
      <div className="heading">
        <h1>To-Do List</h1>
      </div>
      <div className="form">
        <InputArea onAdd={addTask} onKeyPress={handleKeyPress} />
      </div>
      <div>
        <ul>
          {todoTasks.map((todoTasks, i) => (
            <ToDoTask
              key={i}
              id={i}
              text={todoTasks}
              onChecked={deleteTodoTask}
            />
          ))}
        </ul>
      </div>
    </div>
  );
}

export default App;

I also created an input component:

import React, { useState } from "react";

function InputArea(props) {
  const [todoInput, setTodoInput] = useState("");

  function handleChange(event) {
    const newInput = event.target.value;
    setTodoInput(newInput);
  }

  return (
    <div className="form">
      <input
        onKeyDown={(event) => {
          props.onKeyPress(event);
          setTodoInput("");
        }}
        onChange={handleChange}
        type="text"
        value={todoInput}
      />
      <button
        onClick={() => {
          props.onAdd(todoInput);
          setTodoInput("");
        }}
      >
        <span>Add</span>
      </button>
    </div>
  );
}

export default InputArea;

this is my todoTask component:

import React from "react";

function ToDoTask(props) {
  return (
    <div
      onClick={() => {
        props.onChecked(props.id);
      }}
    >
      <li>{props.text}</li>
    </div>
  );
}

export default ToDoTask;

Upvotes: 4

Views: 1162

Answers (1)

Drew Reese
Drew Reese

Reputation: 202836

If the goal is to clear the input when "enter" is pressed then I suggest using a form element. So long as there is just the one input then pressing enter while focused will submit the form. Use the form's submit handler to call the onAdd callback and reset the local todoInput state.

InputArea

function InputArea({ onAdd }) {
  const [todoInput, setTodoInput] = useState("");

  const submitHandler = (e) => {
    e.preventDefault();
    if (todoInput) {
      onAdd(todoInput);
      setTodoInput("");
    }
  };

  function handleChange(event) {
    const { value } = event.target;
    setTodoInput(value);
  }

  return (
    <form onSubmit={submitHandler}>
      <input onChange={handleChange} type="text" value={todoInput} />
      <button type="submit">
        <span>Add</span>
      </button>
    </form>
  );
}

Demo

function InputArea({ onAdd }) {
  const [todoInput, setTodoInput] = React.useState("");

  const submitHandler = (e) => {
    e.preventDefault();
    if (todoInput) {
      onAdd(todoInput);
      setTodoInput("");
    }
  };

  function handleChange(event) {
    const { value } = event.target;
    setTodoInput(value);
  }

  return (
    <form onSubmit={submitHandler}>
      <input onChange={handleChange} type="text" value={todoInput} />
      <button type="submit">
        <span>Add</span>
      </button>
    </form>
  );
}

function ToDoTask(props) {
  return (
    <div
      onClick={() => {
        props.onChecked(props.id);
      }}
    >
      <li>{props.text}</li>
    </div>
  );
}

function App() {
  const [todoTasks, setTodoTasks] = React.useState([]);

  function addTask(todoInput) {
    setTodoTasks((prevTodoTasks) => {
      return [...prevTodoTasks, todoInput];
    });
  }

  function deleteTodoTask(id) {
    setTodoTasks((prevTodoTasks) => {
      return prevTodoTasks.filter((task, i) => {
        return i !== id;
      });
    });
  }

  return (
    <div className="container">
      <div className="heading">
        <h1>To-Do List</h1>
      </div>
      <div className="form">
        <InputArea onAdd={addTask} />
      </div>
      <div>
        <ul>
          {todoTasks.map((todoTasks, i) => (
            <ToDoTask
              key={i}
              id={i}
              text={todoTasks}
              onChecked={deleteTodoTask}
            />
          ))}
        </ul>
      </div>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  rootElement
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="root" />

Upvotes: 2

Related Questions