Не удается обновить изображение на странице редактирования блога

Вопрос или проблема

У меня есть форма для создания/редактирования блога, я добавил свойство isEditing, чтобы, например, изменить текст кнопки отправки с “создать” на “обновить”, если isEditing истинно. Таким образом, мне не нужно будет создавать отдельные формы для обеих этих страниц.

Когда я создаю пост, заголовок, описание и изображение блога добавляются в базу данных, и всё работает как ожидается. Но когда я пытаюсь изменить изображение определенного блога и отправляю форму, заголовок и описание можно обновить, но изображение не обновляется, оно остается прежним, как будто не было обновлено в базе данных вообще.

Я использую prisma + postgresql, nextjs и cloudinary для хранения изображений.

Давайте найдем отличия между страницами редактирования и создания блога:

Компонент EditBlogPage (/app/(pages)/edit/[id]):

"use client";
import FormBlog from "@/components/blogPage/FormBlog";
import { useMutation, useQuery } from "@tanstack/react-query";
import axios from "axios";
import { useRouter } from "next/navigation";
import { useState } from "react";

const EditBlogPage = ({ params }) => {
  const { id } = params;
  const router = useRouter();
  const [imageUrl, setImageUrl] = useState("");

  const { data: dataBlog, isLoading } = useQuery({
    queryKey: ["blogs", id],
    queryFn: async () => {
      const res = await axios.get(`/api/blogs/${id}`);
      return res.data;
    },
  });

  const { mutate: updateBlog } = useMutation({
    mutationFn: (newBlog) => {
      return axios.patch(`/api/blogs/${id}`, newBlog);
    },
    onError: (error) => {
      console.error(error);
    },
    onSuccess: () => {
      router.push("/blog");
      router.refresh();
    },
  });

  const handleEditBlog = (data) => {
    updateBlog({ ...data, imageUrl: imageUrl || dataBlog.imageUrl });
  };

  if (isLoading) {
    return <h1 className="h-screen text-3xl text-center">Загрузка...</h1>;
  }

  return (
    <div className="h-screen flex items-center justify-center flex-col">
      <h1 className="mb-4 text-lg">Изменить блог</h1>
      <FormBlog
        submit={handleEditBlog}
        initialValue={dataBlog}
        isEditing
        setImageUrl={setImageUrl}
      />
    </div>
  );
};

export default EditBlogPage;

Компонент CreateBlog (/app/(pages)/create/page.jsx):

"use client";
import { useMutation } from "@tanstack/react-query";
import FormBlog from "../../../components/blogPage/FormBlog";
import axios from "axios";
import { useRouter } from "next/navigation";
import { useState } from "react";

const CreateBlog = () => {
  const [imageUrl, setImageUrl] = useState("");
  const router = useRouter();

  const handleCreateBlog = (data) => {
    const blogData = {
      ...data,
      imageUrl: imageUrl,
    };
    createBlog(blogData);
  };

  const { mutate: createBlog, isPending } = useMutation({
    mutationFn: (newBlog) => {
      return axios.post("/api/blogs/create", newBlog);
    },
    onError: (error) => {
      console.error(error);
    },
    onSuccess: () => {
      router.push("/blog");
      router.refresh();
    },
  });
  return (
    <div className="h-screen flex items-center justify-center flex-col">

      <FormBlog
        submit={handleCreateBlog}
        initialValue={null}
        isEditing={false}
        setImageUrl={setImageUrl}
      />
    </div>
  );
};

export default CreateBlog;

А теперь FormBlog.jsx, я попытался убрать ненужные части кода, чтобы вы могли сосредоточиться на проблеме:

"use client";
import { CldUploadButton } from "next-cloudinary";
import Image from "next/image";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";

const FormBlog = ({ submit, isEditing, initialValue, setImageUrl }) => {
  const { register, handleSubmit } = useForm({
    defaultValues: initialValue,
  });
  const [publicId, setPublicId] = useState("");

  // Установите URL изображения, когда находитесь в режиме редактирования
  useEffect(() => {
    if (isEditing && initialValue?.imageUrl) {
      const parts = initialValue.imageUrl.split("/");
      const publicIdPart = parts[parts.length - 1].split(".")[0]; // Извлеките публичный ID из URL
      setPublicId(publicIdPart);
      setImageUrl(initialValue.imageUrl); // Установите URL изображения для редактирования
    }
  }, [isEditing, initialValue, setImageUrl]);

  const handleImageUpload = (result) => {
    const info = result.info;

    if ("secure_url" in info && "public_id" in info) {
      const url = info.secure_url;
      const public_id = info.public_id;

      setImageUrl(url);
      setPublicId(public_id);
    }
  };

  const removeImg = async (e) => {
    e.preventDefault();

    try {
      const res = await fetch("/api/blogs/removeImage", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ publicId }),
      });

      if (res.ok) {
        await res.json();

        setImageUrl("");
        setPublicId("");
      } else {
        console.error("Ошибка при удалении изображения");
      }
    } catch (error) {
      console.log(error);
    }
  };

  return (
    <form
      className="w-1/2 mx-auto p-6 bg-white rounded-lg shadow-md"
      onSubmit={handleSubmit(submit)}
    >

      <div className="flex items-center justify-center flex-col">
        <CldUploadButton
          uploadPreset={`${process.env.NEXT_PUBLIC_CLOUDINARY_UPLOAD_PRESET}`}
          className={`relative h-48 w-full border-2 my-4 border-dotted grid place-items-center bg-slate-100 rounded-md ${
            publicId && "pointer-events-none"
          }`}
          onSuccess={handleImageUpload}
        >
          {!publicId && "Загрузить фото"}
          {publicId && (
            <Image
              src={`https://res.cloudinary.com/${process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME}/image/upload/${publicId}`}
              fill
              className="absolute object-cover inset-0"
              alt={publicId}
            />
          )}
        </CldUploadButton>

        {publicId && (
          <button
            onClick={removeImg}
            className="p-4 rounded-lg bg-red-600 text-white my-4"
          >
            Убрать изображение
          </button>
        )}
      </div>

      <button
        type="submit"
        className="w-full bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:ring-2 focus:ring-blue-500"
      >
        {isEditing ? "Обновить" : "Создать"}
      </button>
    </form>
  );
};

export default FormBlog;

Сообщите мне, какую часть кода следует добавить к этому вопросу, возможно, роутеры API и т.д.

Ответ или решение

Чтобы решить проблему с обновлением изображения на странице редактирования блога, давайте внимательно рассмотрим предполагаемую модель данных и обработку API CRUD. Похоже, что логика обновления изображения может быть нарушена в API-методе, который обрабатывает PATCH-запрос.

1. Проверка текущего API для обновления блога

Во-первых, убедитесь, что ваш API-метод, который отвечает за обновление блога, правильно обрабатывает обновления изображения. Например, если вы используете Prisma, ваш метод может выглядеть так:

// pages/api/blogs/[id].js

import db from '../../../lib/prisma'; // Путь к вашей установке Prisma

export default async function handler(req, res) {
  const {
    method,
    query: { id },
    body,
  } = req;

  switch (method) {
    case 'PATCH':
      try {
        const updatedBlog = await db.blog.update({
          where: { id: Number(id) },
          data: {
            title: body.title,
            description: body.description,
            imageUrl: body.imageUrl, // Проверьте, корректно ли здесь указано поле для обновления
          },
        });
        return res.status(200).json(updatedBlog);
      } catch (error) {
        return res.status(500).json({ error: 'Ошибка при обновлении блога' });
      }

    default:
      return res.status(405).end(); // Method Not Allowed
  }
}

2. Проверка на клиенте

Убедитесь, что ваша логика, передающая новые данные на сервер, действительно передает новое поле imageUrl. В вашем компоненте EditBlogPage вы правильно передаете imageUrl как часть объекта данных, но для этого важно, чтобы imageUrl действительно обновлялся при загрузке нового изображения.

3. Убедитесь, что handleImageUpload работает корректно

В компоненте FormBlog, логика обработки загрузки изображения выглядит нормально, но убедитесь, что метод handleImageUpload действительно вызывается и устанавливает новый URL изображения:

const handleImageUpload = (result) => {
  const info = result.info;

  if ("secure_url" in info && "public_id" in info) {
    const url = info.secure_url;
    const public_id = info.public_id;

    setImageUrl(url); // Установите новый URL
    setPublicId(public_id); // Установите новый public_id
  }
};

4. Логирование и отладка

Добавьте отладочные журналы в ваш метод обработки submit как в клиенте, так и на сервере, чтобы убедиться, что в ваши данные действительно попадает новый imageUrl. Например:

const handleEditBlog = (data) => {
  console.log('Data being submitted:', { ...data, imageUrl: imageUrl || dataBlog.imageUrl });
  updateBlog({ ...data, imageUrl: imageUrl || dataBlog.imageUrl });
};

Убедитесь, что imageUrl обновляется, когда вы загружаете новое изображение и передаете правильные данные на сервер для обновления.

5. Дополнительная проверка в FormBlog

В компоненте FormBlog, когда вы загружаете новое изображение, проверьте, что код в useEffect не перезаписывает значение imageUrl, если оно обновляется:

useEffect(() => {
  if (isEditing && initialValue?.imageUrl) {
    setImageUrl(initialValue.imageUrl);
  }
}, [isEditing, initialValue]); // Убедитесь, что здесь не пересоздается состояние

Заключение

Если вышеуказанные шаги не приводят к решению вашей проблемы, предоставьте дополнительные детали о вашем API или конкретные ошибки, с которыми вы сталкиваетесь. Это поможет лучше понять проблему. Также не забудьте проверить все возможные коды состояния HTTP, чтобы лучше понять, откуда может исходить ошибка.

Оцените материал
Добавить комментарий

Капча загружается...