1

I have an existing Task with a title and a description, and I want to navigate to an edit form. By default I want the existing title and description values to populate the inputs using React. The important piece of this code I'm asking about is value={task.title}. Please ignore how the data is being pulled in (I'm new to React and I'm experimenting). The onChange and onSubmit handles work correctly, but the error obviously indicates I'm doing it wrong and it does cause occasional bugs.

I've tried abstracting those values into some sort of formValues state as well, but no matter how the values are being input, if the value={howeverIDoIt} is being directly manipulated I get the error.

import React, { useEffect, useState } from 'react';
import { HEADERS, TODO_URL } from '../urls';
import { useHistory, useParams } from 'react-router-dom';

const TaskEdit = () => {
    const [task, setTask] = useState({});
    const { id } = useParams();
    const history = useHistory();

    useEffect(() => {
        fetch(`${TODO_URL}/api/tasks/${id}/`, {headers: HEADERS})
          .then(response => response.json())
          .then(responseJson => {
              setTask(responseJson);
          });
    }, []);

    const handleChange = (e) => {
        setTask(e.target.value)
    }

    const handleSubmit = (e) => {
        e.preventDefault();
        const body = {
            'title': e.target.form[0].value,
            'description': e.target.form[1].value
        }
        fetch(
            `${TODO_URL}/api/tasks/${id}/edit/`,
            {
                headers: HEADERS,
                method: 'PUT',
                body: JSON.stringify(body)
            }
        ).then(res => res).catch(err => err);
        history.push(`/task/${id}`)
    }

    return (
        <form>
            <div>
                <label>Title</label>
                <input type="text" onChange={handleChange} value={task.title} />
            </div>
            <div>
                <label>Description</label>
                <textarea onChange={handleChange} value={task.description}></textarea>
            </div>
            <button onClick={handleSubmit}>Submit</button>
        </form>
    );
}

export default TaskEdit;

I have tried putting in a default value for useState like so: useState({title: 'title', description: 'description'}) but that doesn't prevent the error, nor does adding this edit form into the Task.js component, where task is most definitely defined.

1 Answer 1

3

You have:

<input type="text" onChange={handleChange} value={task.title} />

Your handleChange method is:

const handleChange = (e) => {
        setTask(e.target.value)
}

When your onChange fires, your task state will be set to a String (the value of <input />)

So when you are referencing task.title after your onChange fires, it will be undefined. The same is true for task.description.

Try this:

const handleTitleChange = (e) => {
  setTask({...task, title: e.target.value})
}

const handleDescriptionChange = (e) => {
  setTask({...task, description: e.target.value})
}

<input type="text" onChange={handleTitleChange} value={task.title} />
<textarea onChange={handleDescriptionChange} value={task.description} />

Alternatively, you could split up the task state to title and description, respectively.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks so much! So just for other people's future reference since my post is kinda all over the place (as is my React knowledge), using your onChange methods with a default state of `useState({title: '', description: ''}) fixes the error. I saw all over the internet about the default state using empty strings, which wasn't working because of how my onChange method was making other aspects of my task object undefined. Thanks so much!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.