Необработанная ошибка времени выполнения TypeError: FormData.set не является функцией? невозможно это исправить

#reactjs #next.js #node-modules #form-data

#reactjs #next.js #узлы-модули #форма-данные

Вопрос:

когда я хочу обновить блог, эта ошибка возникает после перезагрузки браузера, эта ошибка устраняется. по этой причине мне нужно обновлять браузер каждый раз, когда я хочу обновить блог. я использовал FormData.set в handleToggle и handleTagsToggle, он работает нормально, но я не могу решить эту проблему, что мне делать?

 TypeError: formData.set is not a function

Source
components/crud/BlogUpdate.js (186:17) @ Object.handleBody [as onChange]

  184 |     const handleBody = e => {
  185 |         setBody(e)
> 186 |         formData.set('body', e);
      |                 ^
  187 |     };
  188 | 
  189 |     const editBlog = (e) => {
Call Stack
Object.onEditorChangeText
node_modules/react-quill/lib/component.js (384:0)
Object.eval
node_modules/react-quill/lib/mixin.js (28:0)
Object.eval
node_modules/react-quill/lib/mixin.js (54:0)
Emitter.emit
node_modules/quill/dist/quill.js (8671:0)
Emitter.emit
node_modules/quill/dist/quill.js (1943:0)
Quill.modify
node_modules/quill/dist/quill.js (1674:0)
Quill.setContents
node_modules/quill/dist/quill.js (1505:0)
Object.setEditorContents
node_modules/react-quill/lib/mixin.js (78:0)
Object.Quill_componentWillReceiveProps [as componentWillReceiveProps]
node_modules/react-quill/lib/component.js (183:0)
callComponentWillReceiveProps
node_modules/react-dom/cjs/react-dom.development.js (12972:0)
updateClassInstance
node_modules/react-dom/cjs/react-dom.development.js (13178:0)
updateClassComponent
node_modules/react-dom/cjs/react-dom.development.js (17107:0)
beginWork
node_modules/react-dom/cjs/react-dom.development.js (18620:0)
HTMLUnknownElement.callCallback
node_modules/react-dom/cjs/react-dom.development.js (188:0)
Object.invokeGuardedCallbackDev
node_modules/react-dom/cjs/react-dom.development.js (237:0)
invokeGuardedCallback
node_modules/react-dom/cjs/react-dom.development.js (292:0)
beginWork$1
node_modules/react-dom/cjs/react-dom.development.js (23203:0)
performUnitOfWork
node_modules/react-dom/cjs/react-dom.development.js (22154:0)
workLoopSync
node_modules/react-dom/cjs/react-dom.development.js (22130:0)
performSyncWorkOnRoot
node_modules/react-dom/cjs/react-dom.development.js (21756:0)
eval
node_modules/react-dom/cjs/react-dom.development.js (11089:0)
unstable_runWithPriority
node_modules/scheduler/cjs/scheduler.development.js (653:0)
runWithPriority$1
node_modules/react-dom/cjs/react-dom.development.js (11039:0)
flushSyncCallbackQueueImpl
node_modules/react-dom/cjs/react-dom.development.js (11084:0)
flushSyncCallbackQueue
node_modules/react-dom/cjs/react-dom.development.js (11072:0)
scheduleUpdateOnFiber
node_modules/react-dom/cjs/react-dom.development.js (21199:0)
dispatchAction
node_modules/react-dom/cjs/react-dom.development.js (15660:0)
eval
components/crud/BlogUpdate.js (48:20)
Hide collapsed frames


----------


import Link from 'next/link';
import { useState, useEffect } from 'react';
import Router from 'next/router';
import dynamic from 'next/dynamic';
import { withRouter } from 'next/router';
import { getCookie, isAuth } from '../../actions/auth';
import { getCategories } from '../../actions/category';
import { getTags } from '../../actions/tag';
import { singleBlog, updateBlog } from '../../actions/blog';
const ReactQuill = dynamic(() => import('react-quill'), { ssr: false });
import '../../node_modules/react-quill/dist/quill.snow.css';
import {QuillModules, QuillFormats} from '../../helpers/quill.js';

const BlogUpdate = ({router}) => {
    const [categories, setCategories] = useState([]);
    const [tags, setTags] = useState([]);

    const [checked, setChecked] = useState([]); // categories
    const [checkedTag, setCheckedTag] = useState([]); // tags

    const [body, setBody] = useState({});
    const [values, setValues] = useState({
        title: '',
        error: '',
        success: '',
        formData: '',
        title: '',
        body: ''
    });

    const {error, success, formData, title} = values;
    let token = getCookie('token');

    useEffect(() => {
        setValues({ ...values, formData: new FormData() })
        initBlog();
        initCategories();
        initTags();
    }, [router])

    const initBlog = () => {
        if (router.query.slug) {
            singleBlog(router.query.slug).then(data => {
                if (data.error) {
                    console.log(data.error);
                } else {
                    setValues({...values, title: data.title});
                    setBody(data.body);
                    setCategoriesArray(data.categories);
                    setTagsArray(data.tags);
                }
            });
        }
    };

    const setCategoriesArray = blogCategories => {
        let ca = [];
        blogCategories.map((c, i) => {
            ca.push(c._id);
        });
        setChecked(ca);
    };

    const setTagsArray = blogTags => {
        let ta = [];
        blogTags.map((t, i) => {
            ta.push(t._id);
        });
        setCheckedTag(ta);
    };

    const initCategories = () => {
        getCategories().then(data => {
            if (data.error) {
                setValues({ ...values, error: data.error });
            } else {
                setCategories(data);
            }
        });
    };

    const initTags = () => {
        getTags().then(data => {
            if (data.error) {
                setValues({ ...values, error: data.error });
            } else {
                setTags(data);
            }
        });
    };


    const handleToggle = c => () => {
        setValues({ ...values, error: '' });
        // return the first index or -1
        const clickedCategory = checked.indexOf(c);
        const all = [...checked];

        if (clickedCategory === -1) {
            all.push(c);
        } else {
            all.splice(clickedCategory, 1);
        }
        console.log(all);
        setChecked(all);
        formData.set('categories', all);
    };

    const handleTagsToggle = t => () => {
        setValues({ ...values, error: '' });
        // return the first index or -1
        const clickedTag = checkedTag.indexOf(t);
        const all = [...checkedTag];

        if (clickedTag === -1) {
            all.push(t);
        } else {
            all.splice(clickedTag, 1);
        }
        console.log(all);
        setCheckedTag(all);
        formData.set('tags', all);
    };

    const findOutCategory = c => {
        const result = checked.indexOf(c);
        if (result !== -1) {
            return true;
        } else {
            return false;
        }
    };

    const findOutTag = t => {
        const result = checkedTag.indexOf(t);
        if (result !== -1) {
            return true;
        } else {
            return false;
        }
    };

    const showCategories = () => {
        return (
            categories amp;amp;
            categories.map((c, i) => (
                <li key={i} className="list-unstyled">
                    <input 
                        onChange={handleToggle(c._id)} 
                        checked={findOutCategory(c._id)} 
                        type="checkbox" 
                        className="mr-2" 
                    />
                    <label className="form-check-label">{c.name}</label>
                </li>
            ))
        );
    };

    const showTags = () => {
        return (
            tags amp;amp;
            tags.map((t, i) => (
                <li key={i} className="list-unstyled">
                    <input 
                        onChange={handleTagsToggle(t._id)}                       
                        checked={findOutTag(t._id)} 
                        type="checkbox" 
                        className="mr-2" 
                    />
                    <label className="form-check-label">{t.name}</label>
                </li>
            ))
        );
    };

    const handleChange = name => e => {
        // console.log(e.target.value);
        const value = name === 'photo' ? e.target.files[0] : e.target.value;
        formData.set(name, value);
        setValues({ ...values, [name]: value, formData, error: '' });
    };

    const handleBody = e => {
        setBody(e)
        formData.set('body', e);
    };

    const editBlog = (e) => {
        e.preventDefault();
        updateBlog(formData, token, router.query.slug).then(data => {
            if (data.error) {
                setValues({ ...values, error: data.error });
            } else {
                setValues({ ...values, title: '', success: `Blog titled "${data.title}" is successful updated"`})
                if (isAuth() amp;amp; isAuth().role === 1) {
                    Router.replace(`/admin/crud/${router.query.slug}`);
                } else if (isAuth() amp;amp; isAuth().role === 0) {
                    Router.replace(`/user/crud/${router.query.slug}`);
                }
            }
        })
        
        console.log('updateBlog')
    }

    const updateBlogForm = () => {
        return (
            <form onSubmit={editBlog}>
                <div className="form-group">
                    <label className="text-muted">Title</label>
                    <input type="text" className="form-control" value={title} onChange={handleChange('title')} />
                </div>

                <div className="form-group">
                    <ReactQuill
                        modules={QuillModules}
                        formats={QuillFormats}
                        value={body}
                        placeholder="Write something amazing..."
                        onChange={handleBody}
                    />
                </div>

                <div>
                    <button type="submit" className="btn btn-primary">
                        Update
                    </button>
                </div>
            </form>
        );
    };

    return ( 
        <div className="container-fluid pb-5">
            <div className="row">
                <div className="col-md-8">
                    <div className="pt-3">
                        <p>show success and error message</p>
                    </div>
                        {updateBlogForm()}
                </div>

                <div className="col-md-4">
                    <div>
                        <div className="form-group pb-2">
                            <h5>Featured image</h5>
                            <hr />

                            <small className="text-muted">Max size: 1mb</small>
                            <label className="btn btn-outline-info">
                                Upload featured image
                                <input onChange={handleChange('photo')} type="file" accept="image/*" hidden />
                            </label>
                        </div>
                    </div>
                    <div>
                        <h5>Categories</h5>
                        <hr />

                        <ul style={{ maxHeight: '200px', overflowY: 'scroll' }}>{showCategories()}</ul>
                    </div>
                    <div>
                        <h5>Tags</h5>
                        <hr />
                        <ul style={{ maxHeight: '200px', overflowY: 'scroll' }}>{showTags()}</ul>
                    </div>
                </div> 
            </div>
        </div>
    );
};

export default withRouter(BlogUpdate);
 

Комментарии:

1. Попробуйте добавить точку с запятой в строке 185 , после setBody(e) . Дайте мне знать, помогло ли это

2. Сообщение об ошибке, похоже, связано с react-quill и ReactQuill компонентом. Если вы сохраните приведенный выше код и закомментируете formData.set('body', e); handleBody его, он скомпилируется и запустится? Если вы сделаете a console.log(formData); in handleBody , каков будет результат?

Ответ №1:

Проблема

Начальное состояние for values.formData — это пустая строка, поэтому formData.set(...) недопустимый вызов для начального рендеринга.

 const [values, setValues] = useState({
    title: '',
    error: '',
    success: '',
    formData: '', // <-- empty string
    title: '',
    body: ''
});
 

Эффект возникает после первоначального рендеринга

 useEffect(() => {
    setValues({
      ...values,
      formData: new FormData(), // <-- valid formData object after initial render
    });
    initBlog();
    initCategories();
    initTags();
}, [router])
 

Решение

Укажите допустимое начальное состояние

 const [values, setValues] = useState({
    title: '',
    error: '',
    success: '',
    formData: new FormData(),
    title: '',
    body: ''
});
 

Комментарии:

1. Ошибка сервера Ошибка ссылки: FormData не определена Эта ошибка произошла при создании страницы. Любые журналы консоли будут отображаться в окне терминала. Источник

2. @MuradKhan Ах, я вижу, вы делаете SSR, незнакомая территория для меня. Мне придется немного покопаться, возможно FormData , он недоступен в Nodejs.

3. Я решил проблему, перезагрузив страницу. не использовал next.js Ссылка для этого конкретного маршрута. Кстати, спасибо.