#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
его, он скомпилируется и запустится? Если вы сделаете aconsole.log(formData);
inhandleBody
, каков будет результат?
Ответ №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 Ссылка для этого конкретного маршрута. Кстати, спасибо.