Необработанное отклонение (ошибка типа): Не удается прочитать свойства неопределенного (чтение «уменьшить»)

#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 })