react/redux中的formData在expressjs中返回未定义的req.params.id

问题描述 投票:0回答:1

我有一个多部分表单,我正在使用 formData 通过“PUT”请求发送数据。我收到错误模型“Blogpost”的路径“_id”处的值“未定义”(类型字符串)转换为 objectId 失败,当我在控制器上 console.log req.params.id 时,它返回未定义。 我使用react-hook-form、redux-toolkit 和 multer-cloudinary 进行图像上传。

我的前端是:

const BlogpostEdit = () => {
  const { id } = useParams()

  const {
    data: blogpostData,
    isLoading,
    refetch,
    error
  } = useGetBlogpostDetailsQuery(id)

  const [updateBlogpost, { isLoading: loadingUpdate }] =
    useUpdateBlogpostMutation()

  useEffect(() => {
    if (blogpostData) {
      setValue('image', blogpostData.image)
      setValue('title', blogpostData.title)
      setValue('subtitle', blogpostData.subtitle)
      setValue('content', blogpostData.content)
      setValue('category', blogpostData.category)
    }
  }, [blogpostData])

  const {
    register,
    setValue,
    handleSubmit,
    formState: { errors }
  } = useForm()

  const onFormSubmit = async data => {
    if (data.image[0]) {
      const formData = new FormData()
      formData.append('_id', id)
      formData.append('image', data.image[0])
      data = { ...data, image: data.image[0].name }
      formData.append('image', data.image)
      formData.append('title', data.title)
      formData.append('subtitle', data.subtitle)
      formData.append('content', data.content)
      formData.append('category', data.category)
      try {
        const response = await updateBlogpost(formData).unwrap()
        toast.success('Blogpost has been updated')
        refetch()
      } catch (err) {
        toast.error(err?.data?.message || err.error)
      }
    } else {
      try {
        const response = await updateBlogpost({ ...data, _id: id }).unwrap()
        toast.success('Blogpost has been updated')
        refetch()
      } catch (err) {
        toast.error(err?.data?.message || err.error)
      }
    }
  }

  return (
    <FormContainer>
      {loadingUpdate && <Loader />}

      {isLoading ? (
        <Loader />
      ) : error ? (
        <p>{error.data.message}</p>
      ) : (
        <>
          <img src={blogpostData.image.url} style={{ width: '150px' }} />
          <form onSubmit={handleSubmit(onFormSubmit)}>
            <label htmlFor='image' name='image'>
              image
            </label>
            <input type='file' {...register('image')} />
            <p>{errors.image?.message}</p>
            <label htmlFor='title' name='title'>
              Title
            </label>
            <input type='text' {...register('title')} />
            <p>{errors.title?.message}</p>
            <label htmlFor='subtitle' name='subtitle'>
              Subtitle
            </label>
            <input type='text' {...register('subtitle')} />
            <p>{errors.subtitle?.message}</p>
            <label htmlFor='content' name='content'>
              Content
            </label>
            <textarea
              rows='10'
              cols='100'
              type='text'
              {...register('content')}
            />
            <p>{errors.content?.message}</p>
            <label htmlFor='category'>Choose a category:</label>
            <select name='category' {...register('category')}>
              <option value=''></option>
              <option value='game'>Game</option>
              <option value='tv'>TV</option>
              <option value='anime'>Anime</option>
              <option value='book'>Book</option>
            </select>
            <p>{errors.category?.message}</p>
            <button type='submit'>Submit</button>
          </form>
        </>
      )}
    </FormContainer>
  )
}

export default BlogpostEdit

切片/突变是:

updateBlogpost: builder.mutation({
      query: (data) => ({
        url: `${BLOGPOSTS_URL}/${data._id}`,
        method: 'PUT',
        body: data,
      }),
      invalidatesTags: ['Blogposts'],
    }),

后端控制器:

const updateBlogpost = asyncHandler(async (req, res) => {
  const { id } = req.params;
  const blogpost = await Blogpost.findByIdAndUpdate(id, { ...req.body });
  if (req.file) {
    blogpost.image.url = req.file.path;
    blogpost.image.filename = req.file.filename;
  }
  const updatedBlogpost = await blogpost.save();
  if (updatedBlogpost) {
    res.status(200).json(updatedBlogpost);
  } else {
    res.status(404);
    throw new Error('Resouce not found');
  }
});

以及路线:

router
  .route('/:id')
  .put(registered, admin, upload.single('image'), updateBlogpost);

提交表单数据如下所示:

和表单数据:

这是控制台上的错误:

以及来自 try/catch 的错误:

在控制器上我得到req.body,图像成功上传,但req.params.id未定义。例如,如果我不添加图像而仅编辑标题,则一切正常。当我想要包含图像时会发生这些错误。我在“POST”请求上使用完全相同的代码,并且效果很好。 现在我知道我可以首先使用不同的上传路径和不同的路径来更新模型来上传文件,但我只是无法弄清楚为什么会发生这些错误。

mongoose react-redux undefined multipartform-data objectid
1个回答
0
投票

您正在将一个

FormData
对象传递到突变端点,该对象不是,就像您可以简单地从中解构属性的常规 Javascript 对象一样。您应该使用访问器来访问特定的表单数据值。

const formData = new FormData();
formData.append("_id", "1234");

console.log(formData._id); // undefined
console.log(formData.get("_id")); // "1234"

更新端点以正确访问id表单数据。

updateBlogpost: builder.mutation({
  query: (data) => ({
    url: `${BLOGPOSTS_URL}/${data.get("_id")}`,
    method: 'PUT',
    body: data,
  }),
  invalidatesTags: ['Blogposts'],
}),
© www.soinside.com 2019 - 2024. All rights reserved.