#reactjs #typescript #validation
#реагирует на #машинописный текст #утверждение
Вопрос:
Я работаю над проверкой yup. Всякий раз, когда дело доходит до проверки списка файлов, если я оставлял поле ввода пустым, я получал следующую ошибку: введите описание изображения здесь
Вот мой код:
import React, { useEffect, useMemo, useState } from 'react'; import { useLocation } from 'react-router'; import { useDispatch, useSelector } from '@app/hooks'; import { Button, Dimmer, Dropdown, DropdownItemProps, DropdownProps, Form, Header, Loader, Modal } from 'semantic-ui-react'; import { NewBook, TestBook, UpdateParam } from '@app/reducers/master-data/book/book.model'; import * as yup from "yup"; import { useForm } from 'react-hook-form'; import { yupResolver } from '@hookform/resolvers/yup'; import { useHistory } from 'react-router-dom'; import { _getAllGenres } from '@app/reducers/master-data/genre/genre.slice'; import { _getAllPublisher } from '@app/reducers/master-data/publisher/publisher.slice'; import { _getAllAuthors } from '@app/reducers/master-data/author/author.slice'; import { _getAllDepartment } from '@app/reducers/master-data/department/department.slice'; import { _updateBook, _getAllBooks, _getBookDetail, _uploadBookFile } from '@app/reducers/master-data/book/book.slice'; import { Wrapper } from '@app/components/data-table/StyledComponent'; import { IBookParam } from '@app/reducers/master-data/book/book.service'; interface IProps { } interface ErrMessage { type: string, message: string } const schema = yup.object().shape({ title: yup.string().required('Title cannot blank'), publishYear: yup.number(), isPublic: yup.boolean(), language: yup.string(), authorIDs: yup.array(), genreIDs: yup.array(), description: yup.string(), // departmentIDs: yup.array(), publisherID: yup.number(), file: yup .mixed() .required("A random message") .nullable(false) .test("Empty file", "You need to provide a file", (value: FileList) =gt; { let x = value.length !== 0 debugger return value.length !== 0; }) .test("type", "Only support PDF file", (value: FileList) =gt; { return value[0].type === "application/pdf" }) }); const UpdateBookPage: React.FClt;IPropsgt; = (props) =gt; { const dispath = useDispatch() const history = useHistory(); useEffect(() =gt; { dispath(_getAllGenres()); dispath(_getAllPublisher()); dispath(_getAllAuthors()); dispath(_getAllDepartment()); // dispath(_getAllBooks()); dispath(_getBookDetail(id)); }, []) const search = useLocation().search; const query = new URLSearchParams(search); const id = query.get('id') || ''; const genres = useSelector(state =gt; state.genre).genres; const publishers = useSelector(state =gt; state.publisher).publishers; const authors = useSelector(state =gt; state.author).authors; const departments = useSelector(state =gt; state.department).departments; const book = useSelector(state =gt; state.book.selectedBook); const isLoading = useSelector(state =gt; state.book.isLoading); const statusCode = useSelector(state =gt; state.book.statusCode); // console.log(book) const defaultDepartments = useMemolt;number[]gt;(() =gt; { let temp: number[] = [] for (let x of book.departments) { temp.push(x.id) }; return temp; }, [book.departments]) const defaultAuthors = useMemolt;number[]gt;(() =gt; { let temp: number[] = [] for (let x of book.authors) { temp.push(Number(x.id)) }; return temp; }, [book.authors]) const defaultGenres = useMemolt;number[]gt;(() =gt; { let temp: number[] = [] for (let x of book.genres) { temp.push(Number(x.id)) }; return temp; }, [book.genres]) const departmentOptions = useMemolt;DropdownItemProps[]gt;(() =gt; { let temp: DropdownItemProps[] = [] for (let x of departments) { temp.push({ key: x.id, text: x.name, value: x.id }) }; return temp; }, [departments]) const genreOptions = useMemolt;DropdownItemProps[]gt;(() =gt; { let temp: DropdownItemProps[] = [] for (let x of genres) { temp.push({ key: x.id, text: x.name, value: x.id }) }; return temp; }, [genres]) const authorOptions = useMemolt;DropdownItemProps[]gt;(() =gt; { let temp: DropdownItemProps[] = [] for (let x of authors) { temp.push({ key: x.id, text: x.fullName, value: x.id }) }; return temp; }, [authors]) const [openForm, setOpenForm] = useStatelt;booleangt;(false) const [authorSelected, setAuthorSelected] = useStatelt;Number[]gt;([...defaultAuthors]); const [genreSelected, setGenreSelected] = useStatelt;Number[]gt;([...defaultGenres]); const [departmentSelected, setDepartmentSelected] = useStatelt;Number[]gt;([...defaultDepartments]); const [selectedFile, setSelectedFile] = useStatelt;File | nullgt;(null); const [fileErrorText, setFileErrorText] = useStatelt;stringgt;(''); // const [selectedFile, setSelectedFile] = useStatelt;File|nullgt;(null); const [isOpen, setIsOpen] = useStatelt;booleangt;(false); const [alertText, setAlertText] = useStatelt;stringgt;(''); const [isFailed, setIsFailed] = useStatelt;booleangt;(false); const [errMessage, setErrMessage] = useStatelt;ErrMessagegt;({ type: '', message: '' }) const { register, handleSubmit, formState: { errors }, setValue, trigger } = useFormlt;TestBookgt;({ resolver: yupResolver(schema), // defaultValues: defaultBook }); useEffect(() =gt; { if (book) { setInitValue() } }, [book]) const setInitValue = () =gt; { setValue('title', book.title) setValue('publishYear', book.publishYear) setValue('authorIDs', [...defaultAuthors]) setValue('language', 'vi') setValue('departmentIDs', [...defaultDepartments]) setValue('description', book.description) setValue('genreIDs', [...defaultGenres]) setValue('isPublic', book.isPublic) setValue('publisherID', Number(book.publisher.id)) } // console.log(defaultAuthors, defaultDepartments, defaultGenres) const handleSubmitBtn = async (data: NewBook) =gt; { debugger console.log(data); const valid = validateData(); debugger if (valid) { data.authorIDs = authorSelected.concat(defaultAuthors); data.genreIDs = genreSelected.concat(defaultGenres) data.departmentIDs = departmentSelected.concat(defaultDepartments) const updateParam: UpdateParam = { id: id, newBook: data } console.log(data); console.log(selectedFile); try { debugger await dispath(_updateBook(updateParam)).then(() =gt; { if (statusCode == 200) { if (selectedFile != null) { let formData = new FormData(); formData.append("FILE", selectedFile); formData.append("NAME", selectedFile.name); const param: IBookParam = { id: localStorage.getItem("BOOKID") || '', file: formData } console.log(param.file); console.log(param.id); dispath(_uploadBookFile(param)).then(() =gt; { if (statusCode == 200) { setIsOpen(true); console.log(isOpen); setAlertText("Update successfully") } else { setIsOpen(true) setAlertText("An error has occured. Please try again later"); setIsFailed(true); } }) } else { return; } } console.log(data); }) } catch { setIsOpen(true) setAlertText("An error has occured. Please try again later"); setIsFailed(true); } } } const validateData = (): boolean =gt; { let x = authorSelected.concat(defaultAuthors) let y = genreSelected.concat(defaultGenres) let z = departmentSelected.concat(defaultDepartments) debugger if (authorSelected.concat(defaultAuthors).includes(0)) { setErrMessage({ type: "AUTHOR", message: "At least one author must be selected" }); return false; } else if (genreSelected.concat(defaultGenres).includes(0)) { setErrMessage({ type: "GENRE", message: "At least one genre must be selected", }); return false; } else if (departmentSelected.concat(defaultDepartments).includes(0)) { setErrMessage({ type: "DEPARTMENT", message: "At least one department must be selected", }); return false; } return true; } const handleAddItem = (data: DropdownProps, type: string) =gt; { let val = JSON.stringify(data.value) let numArr: Number[] = [] val = val.substring(1, val.length - 1) let valArr = val.split(','); // console.log(valArr); for (let x of valArr) { numArr.push(Number(x)) // console.log(numArr) } console.log(numArr) // const y: Number[] = numArr switch (type) { case "AUTHOR": setValue("authorIDs", numArr) setAuthorSelected(numArr) break; case "GENRE": setValue("genreIDs", numArr) setGenreSelected(numArr); break; case "DEPARTMENT": // if(numArr.length gt; 5){ // setErrMessage({ // type: "Department", // message: "You can only select maximum of 5 departments" // }) // break; // } setValue("departmentIDs", numArr) setDepartmentSelected(numArr); break; } } const handleSelectFile = (event: any) =gt; { console.log(event.target.files[0]); setSelectedFile(event.target.files[0]); } const handleCancelAction = () =gt; { history.push('/master-data/manage-book') } useEffect(() =gt; { console.log(authorSelected) console.log(genreSelected) console.log(departmentSelected) }, [authorSelected, genreSelected, departmentSelected]) return ( lt;div className="form-create-book"gt; lt;Headergt;Update booklt;/Headergt; { isLoading amp;amp; ( lt;Wrapper style={{ padding: '40px 0' }}gt; lt;Dimmer inverted active={true}gt; lt;Loadergt;Loadinglt;/Loadergt; lt;/Dimmergt; lt;/Wrappergt;) } { !isLoading amp;amp; ( lt;divgt; lt;Modal size={"tiny"} open={isOpen} gt; lt;Modal.Contentgt; lt;h2 style={{textAlign: 'center'}}gt;{alertText}lt;/h2gt; lt;/Modal.Contentgt; lt;Modal.Actionsgt; {!isFailed amp;amp; lt;Button negative onClick={() =gt; setIsOpen(false)}gt; Close lt;/Buttongt; } lt;Button positive onClick={() =gt; history.push("/librarian/master-data/manage-book")}gt; Ok lt;/Buttongt; lt;/Modal.Actionsgt; lt;/Modalgt; lt;Form className="create-book-form" onSubmit={handleSubmit(handleSubmitBtn)}gt; lt;Form.Fieldgt; lt;label className='dot-required'gt;Titlelt;/labelgt; lt;input {...register('title')} className="text-field" /gt; lt;pgt;{errors.title?.message}lt;/pgt; lt;/Form.Fieldgt; lt;Form.Fieldgt; lt;labelgt;Descriptionlt;/labelgt; lt;textarea {...register('description')} className="textarea-field" /gt; lt;pgt;{errors.description?.message}lt;/pgt; lt;/Form.Fieldgt; lt;Form.Fieldgt; lt;label className='dot-required'gt;Publish Yearlt;/labelgt; lt;input className="text-field" {...register('publishYear')} /gt; lt;pgt;{errors.publishYear?.message}lt;/pgt; lt;/Form.Fieldgt; lt;Form.Fieldgt; lt;label className='dot-required'gt;PDF Filelt;/labelgt; lt;input {...register('file')} className="text-field" accept="application/pdf" type="file" name="file" onChange={handleSelectFile} /gt; lt;pgt;{errors.file?.message}lt;/pgt; lt;/Form.Fieldgt; lt;Form.Fieldgt; lt;label className='dot-required'gt;Access Permissionlt;/labelgt; lt;select defaultValue={book.isPublic ? 1 : 0} className="text-field" {...register('isPublic')}gt; lt;option value={1}gt;Publiclt;/optiongt; lt;option value={0}gt;Restrictedlt;/optiongt; lt;/selectgt; lt;pgt;{errors.isPublic?.message}lt;/pgt; lt;/Form.Fieldgt; lt;Form.Fieldgt; lt;label className='dot-required'gt;Publisherlt;/labelgt; lt;select className="text-field" {...register('publisherID')} gt; { publishers.map((e) =gt; { if (e.id === book.publisher.id) return (lt;option selected value={e.id}gt;{e.name}lt;/optiongt;) else return (lt;option value={e.id}gt;{e.name}lt;/optiongt;) } ) } lt;/selectgt; lt;pgt;{errors.publisherID?.message}lt;/pgt; lt;/Form.Fieldgt; lt;Form.Fieldgt; lt;label className='dot-required'gt;Authorslt;/labelgt; lt;Dropdown className="text-field" onChange={(e, data) =gt; handleAddItem(data, "AUTHOR")} placeholder='Authors' fluid multiple selection options={authorOptions} defaultValue={defaultAuthors} /gt; lt;pgt;{errMessage.type == "AUTHOR" ? errMessage.message : ''}lt;/pgt; lt;/Form.Fieldgt; lt;Form.Fieldgt; lt;label className='dot-required'gt;Genrelt;/labelgt; lt;Dropdown className="text-field" onChange={(e, data) =gt; handleAddItem(data, "GENRE")} placeholder='Genres' fluid multiple selection options={genreOptions} defaultValue={defaultGenres} /gt; lt;pgt;{errMessage.type == "GENRE" ? errMessage.message : ''}lt;/pgt; lt;/Form.Fieldgt; lt;Form.Fieldgt; lt;label className='dot-required'gt;Departmentlt;/labelgt; lt;Dropdown className="text-field" onChange={(e, data) =gt; handleAddItem(data, "DEPARTMENT")} placeholder='Genres' fluid multiple selection options={departmentOptions} defaultValue={defaultDepartments} /gt; lt;pgt;{errMessage.type == "DEPARTMENT" ? errMessage.message : ''}lt;/pgt; lt;/Form.Fieldgt; lt;Button content="Submit" // onClick={handleSubmit(handleSubmitBtn)} className="ui inverted green button" /gt; lt;Button color="black" content="Cancel" onClick={() =gt; handleCancelAction()} className="negative ui button" /gt; lt;/Formgt; lt;/divgt; ) } lt;/divgt; ); }; export default UpdateBookPage;
Когда я проверяю вкладку «Источник», я обнаруживаю, что проблема исходит отсюда:
Но я не знаю, как это решить.
Комментарии:
1. Есть ли у вас какие-либо идеи о том, где
reduce
функция используется для неопределенного объекта? Название и описание не соответствуют снимку экрана. Можете ли вы включить трассировку стека ошибки?
Ответ №1:
заменять
.required("A random message") .nullable(false)
Для
.test("fileLength", "A random message", (value) =gt; { return !!value.length })