Я получаю предупреждение: компонент изменяет неконтролируемый ввод текста типа для управления - PullRequest
2 голосов
/ 13 июня 2019

Я создал простое приложение todo, используя стек MERN с роутером, и смог его запустить, кроме части редактирования. У меня есть 3 маршрута, страница «Todos», где я использую axios, чтобы получить данные от моего экспресс-маршрута на сервере. Страница «Добавить» для создания новой задачи и страница «Редактировать» для редактирования и удаления. Вот моя страница задач, где у каждой задачи есть кнопка, которая принимает идентификатор в качестве параметра url на странице редактирования.

enter image description here

Этот маленький значок карандаша / бумаги на каждой задачи представляет собой ссылку на кнопку, которая определяет идентификатор клика. Вот моя страница редактирования с данными.

enter image description here

Предупреждение:

enter image description here

Вот моя страница Todos Я использую пользовательский хук для получения данных с маршрута экспресс-сервера:

import React from 'react';
import useGetAPI from '../custom_hooks/useGetAPI';
import Todo from './todo_item/Todo';

const Todos = () =>{

    const data = useGetAPI('http://localhost:4000');

    return (
        <div className="page">
            <div className="page-header">
                <h1>Todo Lists</h1>
            </div>
            <div className="page-content">
                <ul className="todo-list">
                    {
                        data.map((todo)=><Todo todo={todo} key={todo._id}/>)
                    }
                </ul>
            </div>
        </div>
    );
}

export default Todos;

Вот мои собственные хуки для выборки данных - используемые в Todos.

import {useState,useEffect} from 'react';
import axios from 'axios';

const useGetAPI = (url)=>{
    const [data,setData] = useState([]);

    useEffect(()=>{
        const fetchData = async ()=>{
            const response = await axios.get(url);
            const data = [...response.data];
            const error = response.error;
            if(error)
                console.log(error)
            else{
                console.log(data);
                setData(data);  
            }
        };
        fetchData();
    },[url])

    return data;
}

export default useGetAPI;

Вот моя Страница редактирования

import React,{useState, useEffect, useContext, useCallback} from 'react';
import useGetApiWithParams from '../custom_hooks/useGetApiWithParams';
import {FaTelegramPlane} from 'react-icons/fa';
import axios from 'axios';
import { matchPath } from 'react-router'


const EditTodo = (props) =>{


const todoID = props.match.params.id;

    const [todo,setTodo] = useState(null);

    const responseData = useGetApiWithParams('http://localhost:4000/edit',todoID);
    console.log(`Todo id: ${todoID}`);

    /* Set default data from database */
    useEffect(()=>{
        setTodo(responseData);
    },[responseData,setTodo]);

    const [description,setDescription] = useState('');
    const [responsible,setResponsible] = useState('');
    const [priority,setPriority] = useState('');
    const [completed,setCompleted] = useState(false);


    const handleDescription = useCallback((e)=>{
        setDescription(e.target.value);
    },[setDescription]);

    const handleResponsible = useCallback((e)=>{
        setResponsible(e.target.value);
    },[setResponsible]);

    const handlePriority = useCallback((e)=>{
        setPriority(e.target.value);
    },[setPriority]);

    const handleCompleted = useCallback((e)=>{
        setCompleted(!completed);
    },[completed,setCompleted])

    const handleSubmit = useCallback((e)=>{     
        e.preventDefault();

        console.log('Form submitted');
        console.log(`Description ${description}`);
        console.log(`Description ${responsible}`);
        console.log(`Description ${priority}`);
        console.log(`Description ${completed}`);

        const updatedTodo = {
            description,
            responsible,
            priority,
            completed: false
        }

        axios.put(`http://localhost/4000/edit/${props.match.params.id}`, updatedTodo)
        .then(res=>console.log(res.data))
        .catch(function (error) {
            console.log(error);
        });

    },[description,responsible,priority,completed,props.match.params.id]);

    return (
        <div className="page">
            <div className="page-header">
                <h1>Edit Todo</h1>
            </div>
            <div className="page-content">
                <form id="edit-todo-form" className="todo-form" onSubmit={handleSubmit}>
                    <div className="form-group">
                        <label htmlFor="description">Description:</label>
                        <input id="description" type="text" className="form-control" onChange={handleDescription} value={responseData.description} />
                    </div>
                    <div className="form-group">
                        <label htmlFor="responsible">Responsible:</label>
                        <input id="responsible" type="text" className="form-control" onChange={handleResponsible} value={responseData.responsible} />
                    </div>
                    <div className="form-group">
                        <label htmlFor="priorities">Priorities:</label>
                        <div id="priorities" className="form-radios">
                            <label htmlFor="radio1" className="radio-label">
                                <input name="priorityOptions" type="radio" id="radio1" value={responseData.priority} checked={priority === 'Low'} onChange={handlePriority}/>
                                <span className="radiomark"></span>
                                <span className="radiotext">Low</span>
                            </label>
                            <label htmlFor="radio2" className="radio-label">
                                <input type="radio" id="radio2" value={responseData.priority} checked={priority === 'Medium'} onChange={handlePriority}/>
                                <span className="radiomark"></span>
                                <span className="radiotext">Medium</span>
                            </label>
                            <label htmlFor="radio3" className="radio-label">
                                <input type="radio" id="radio3" value={responseData.priority} checked={priority === 'High'} onChange={handlePriority}/>
                                <span className="radiomark"></span>
                                <span className="radiotext">High</span>
                            </label>
                        </div>
                    </div>
                    <div className="form-group">
                        <label htmlFor="todo_completed">Status:</label>
                        <div id="todo_completed">
                            <label htmlFor="checkcompleted" className="check-label">
                                <input type="checkbox" id="checkcompleted" value={responseData.completed} onChange={handleCompleted}/>
                                <span className="checkmark"></span>
                                <span className="checktext">Completed</span>
                            </label>
                        </div>
                    </div>
                    <div className="form-group">
                        <button type="submit" className="form-btn"><FaTelegramPlane />Save Changes</button>
                    </div>
                </form>
            </div>
        </div>
    );
}

export default EditTodo;

Вот мой пользовательский хук для извлечения данных на основе идентификатора Todo, который я получаю из URL:

import { useState,useEffect } from 'react';
import axios from 'axios';

const useGetApiWithParams = (url,params)=>{
    const [data,setData] = useState([]);

    useEffect(()=>{
        const fetchData = async ()=>{
            const response = await axios.get(`${url}/${params}`);
            const data = response.data;
            const error = response.error;
            if(error)
                console.log(`Error: ${error}`)
            else{
                console.log(...data);
                setData(...data);   
            }
        };
        fetchData();
    },[url,params])

    return data;
}

export default useGetApiWithParams;

И URL с параметром id из MongoDB:

enter image description here

Как это решить? Я попытался заполнить и установить его значение для данных ответа от API, но это работает только для текстовых полей, а как насчет переключателей и флажков? Кажется, они не устанавливают значение по умолчанию. Например, переключатель для установки приоритета value={responseData.priority} не устанавливает значение, как вы видите здесь:

enter image description here

Я бы хотел, чтобы это произошло: со страницы Todos, нажав кнопку редактирования, откройте страницу редактирования с формой, уже заполненной значениями на основе идентификатора задачи из параметра url, и сможете также редактировать значения. Нужна помощь, спасибо!

...