3

我尝试重写此提交函数以使用反应查询 useMutation,但出现错误。有人知道如何将其更改为使用 useMutation 编写。非常感谢您对这个问题的每一个提示和每一个答案。

async function handleSubmit(e) {
    e.preventDefault();
    try {
      if (file) {
        // if file is set send it to cloudinary api
        const url = `https://api.cloudinary.com/v1_1/${CLOUD_NAME}/upload`;
        loading(true);
        const formData = new FormData();
        formData.append("file", file);
        formData.append("upload_preset", UPLOAD_PRESET);

        const res = await fetch(url, {
          method: "POST",
          body: formData,
        });
        // get data and pull out 1000w image url
        const data = await res.json();
        const fileUrl = await data.eager[0].secure_url;
        console.log(fileUrl);
        setError("");
        if (album.trim() !== "" && color.trim() !== "" && fileUrl) {
          // Craeting Date form
          const albumData = new FormData();
          albumData.append("name", album);
          albumData.append("bckImgUrl", fileUrl);
          albumData.append("color", color);
          // change albumData to json
          const object = {};
          albumData.forEach((value, key) => (object[key] = value));
          // sending data to /api/v1/albums
          const res = await fetch(`${SERVER_API}/api/v1/albums`, {
            method: "POST",
            body: JSON.stringify(object),
            headers: {
              "Content-Type": "application/json",
            },
          });
          if (!res.ok) {
            const message = `An error has occured: ${res.status}`;
            setError(message);
          }
          const data = await res.json();
          const id = await data.data._id;
          loading(false);
          history.push(`/albums/${id}`);
        } else {
          setError("Please enter all the field values.");
        }
      } else {
        setError("Please select a file to add.");
      }
    } catch (error) {
      error.response && setError(error.response.data);
    }
  }
4

2 回答 2

2

一点重构建议:)

import React from "react";
import { useHistory } from "react-router-dom";
import { UPLOAD_PRESET, CLOUD_NAME, SERVER_API } from "../../config";

// to don't redefine this function on each rerender they can be defined out of component
const uploadImage = async file => {
    const url = `https://api.cloudinary.com/v1_1/${CLOUD_NAME}/upload`;
    const formData = new FormData();
    formData.append("file", file);
    formData.append("upload_preset", UPLOAD_PRESET);

    const res = await fetch(url, {
        method: "POST",
        body: formData,
    });

    if (!res.ok) {
        throw new Error(`Can't upload image. ${res.status}`)
    }

    const data = await res.json();
    return await data.eager[0].secure_url;
}

const createAlbum = async data => {
    const res = await fetch(`${SERVER_API}/api/v1/albums`, {
        method: "POST",
        body: JSON.stringify(data),
        headers: {
            "Content-Type": "application/json",
        },
    });

    if (!res.ok) {
        throw new Error(`An error has occurred: ${res.status}`)
    }

    const json = await res.json();
    return json.data._id;
}


const Form = ({ file, loading: setLoading, setError, album, color, children }) => {
    let history = useHistory();

    const clearError = () => setError("")
    
    const handleSubmit = async e => {
        e.preventDefault();
        clearError();
        try {
            if (!file) {
                throw new Error("Please select a file to add.");
            }

            if (!album.trim() || !color.trim()){
                throw new Error("Please enter all the field values.");
            }

            setLoading(true);

            const fileUrl = await uploadImage(file);

            const data = {
                "name": album,
                "bckImgUrl": fileUrl,
                "color": color
            };

            const albumId = await createAlbum(data);

            history.push(`/albums/${albumId}`);

        } catch (error) {
            setError(error.message);
        } finally {
            setLoading(false)
        }
    }


    return <form onSubmit={handleSubmit}>{children}</form>
}

export default Form

于 2020-12-21T23:45:29.513 回答
2

类似的东西。尽可能简单

演示的Codesandbox链接

import { Fragment, useState } from "react";
import axios from "axios";
import { useMutation } from "react-query"; 

const senRequest = async () => {
  return await axios.get("https://jsonplaceholder.typicode.com/posts");
};

export default function App() {
  const [val, setVal] = useState("");
  const [result, setResult] = useState([]);

  const { mutate } = useMutation(senRequest); // if you need to send data configure it from here
  const handleSubmit = (e) => {
    e.preventDefault();
    mutate(senRequest, { // And send it in here.
      onSuccess: ({ data }) => {
        setResult(data.slice(0, 5));
      }
    });
  };
  return (
    <div className="App">
      <form onSubmit={handleSubmit}>
        <input value={val} onChange={(e) => setVal(e.target.value)} />
        <button type="submit">Submit</button>
      </form>
      {result.map((el) => (
        <Fragment key={el.id}>
          <div
            style={{
              width: "100%",
              borderBottom: "1px solid gray"
            }}
          >
            <span>{el.title}</span>
            <span>{el.body}</span>
          </div>
        </Fragment>
      ))}
    </div>
  );
}
于 2021-04-26T13:31:37.987 回答