728x90
TypeError: Cannot read properties of undefined (reading 'value')

 

❓ 상황

Todo를 이용하여 Jest 학습 도중 form 태그 내부의 input 요소의 value를 추출하기 위해 e.target.name.value 사용했으나 오류가 발생했다.

TypeError: Cannot read properties of undefined (reading 'value')
  const handleCreateTodo = async (e) => {
    e.preventDefault();

    try {
      const todo = await createTodo(e.target.newTodo.trim());

      setTodos([...todos, todo]);
    } catch (err) {
      console.error(err);
    }
  };
const TodoInput = ({ handleCreateTodo }) => {
  return (
    <form onSubmit={handleCreateTodo}>
      <Input
        data-testid={TEST_ID.NEW_TODO_INPUT}
        name="newTodo"
        placeholder="할일을 추가해보세요"
      />
      <Button data-testid={TEST_ID.NEW_TODO_ADD_BUTTON} type="submit" margin="15px 0 40px">
        추가
      </Button>
    </form>
  );
};

 

🔎 원인 파악

자바스크립트에서는 form.elements.name.value로 추출할 수 있고,

리액트에서는 form.name.value으로 추출할 수 있다.

 

그 이유는 리액트에서 event를 자기 입맛대로 추상화를 했기 때문에 가능한 일이었다.

 

Jest는 모든 자바스크립트 라이브러리나 프레임워크에서 동작할 수 있도록 자바스크립트로 구성되어 있다.

그래서 리액트 문법인 form.name.value로 추출되지 않는 것이다.

 

✨ 해결 방법

기존의 e.target.name.value 으로 input 요소의 value를 추출하는 방식에서 controlled 방식으로 변경하여 해당 문제를 해결했다.

const useTodo = () => {
  const [todos, setTodos] = useState([]);
  const [todoInput, setTodoInput] = useState("");

  const handleNewTodoChange = (e) => {
    setTodoInput(e.target.value);
  };

  const handleCreateTodo = async (e) => {
    e.preventDefault();

    try {
      const todo = await createTodo(todoInput.trim());

      setTodos([...todos, todo]);
    } catch (err) {
      console.error(err);
    }
  };
const TodoInput = ({ todoInput, handleNewTodoChange, handleCreateTodo }) => {
  return (
    <form onSubmit={handleCreateTodo}>
      <Input
        data-testid={TEST_ID.NEW_TODO_INPUT}
        value={todoInput}
        placeholder="할일을 추가해보세요"
        onChange={handleNewTodoChange}
      />
      <Button data-testid={TEST_ID.NEW_TODO_ADD_BUTTON} type="submit" margin="15px 0 40px">
        추가
      </Button>
    </form>
  );
};
복사했습니다!