Formidable 已库存,根本没有任何响应,API 始终处于待定状态,数周内都没有找到锁定解决方案。
我创建了一个简单的个人资料页面,其中包含表单内的图像,以将其上传到下一个 js 中的 api 处理程序,以便拥有一个完整的堆栈 Web 应用程序,但它始终处于挂起状态:
这是前端代码:
import React, {FormEvent, useRef, useState} from "react";
import {useSession} from "next-auth/react";
import Paper from "@mui/material/Paper";
import {Avatar, Box, Button, Grid, TextField, Typography,} from "@mui/material";
import FormData from "form-data";
const Profile = () => {
const {data: session} = useSession();
const filePathRef = useRef<HTMLInputElement | null>(null);
const initialState = {
firstName: session?.user.firstname == null ? "" : session?.user.firstname,
lastName: session?.user.lastname == null ? "" : session?.user.lastname,
currentPassword: "",
profilePicUrl: session?.user.profileImage == null ? "" : session?.user.profileImage
}
// @ts-ignore
const handleImageChange = (e) => {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onloadend = () => {
const uri = URL.createObjectURL(file)
setFormData((prevState) => ({
...prevState,
profilePicUrl: uri
}));
setFile(file)
};
reader.readAsDataURL(file);
} else {
setFormData((prevState) => ({
...prevState,
profilePicUrl: ""
}));
}
};
const [formData,
setFormData] =
useState(initialState);
const [file,
setFile] =
useState<File | null>(null);
const requestState = {
isError: false,
message: ""
}
const [state,
setState
] = useState(requestState)
// @ts-ignore
const handleFormChange = (event) => {
const {name, value} = event.target;
setFormData((prevState) => ({
...prevState,
[name]: value,
}));
};
function isFormChanged() {
return formData.firstName != initialState.firstName ||
formData.lastName != initialState.lastName ||
formData.profilePicUrl != initialState.profilePicUrl
}
const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
console.log("dasdas")
e.preventDefault();
if (isFormChanged()) {
const data = new FormData()
console.log("formData " + formData)
if (file) {
data.append("firstName", formData.firstName)
data.append("lastName", formData.lastName)
data.append("password", formData.currentPassword)
}
if (file != null) { // @ts-ignore
data.append("file", file)
}
const response = await fetch(
'/api/admin', {
method: 'POST',
body: data
});
if (response.ok) {
setState((prevState) => ({
...prevState,
isError: false,
message: 'Update successful!'
}));
} else {
setState((prevState) => ({
...prevState,
isError: true,
message: 'Update failed wrong current password'
}));
}
}
};
return (
<>
<h1>Profile</h1>
<Box>
<Typography variant={"h4"} sx={{paddingBottom: 4}}>
Hey {session ? session?.user?.firstname + " " + session?.user?.lastname : "User"}, welcome to your profile
👋
</Typography>
<Paper sx={{padding: "1rem 2rem"}}>
<Grid container justifyContent="center">
<Grid item xs={12} sm={8} md={6}>
<Box display="flex" flexDirection="column" alignItems="center">
<Avatar
sx={{
height: 100,
width: 100,
marginBottom: 2,
}}
onClick={() => {
filePathRef.current?.click()
}}
src={formData.profilePicUrl}
/>
<Typography variant={"h6"} sx={{
paddingBottom: 4,
color: state.isError ? 'red' : 'green'
}}>
{state.message}
</Typography>
</Box>
<form
method="post"
onSubmit={handleSubmit}
style={{maxWidth: 600, margin: "0 auto"}}>
<Grid container spacing={3}>
<Grid item xs={12} sm={6}>
<TextField
required
fullWidth
label="First Name"
name="firstName"
value={formData.firstName}
onChange={handleFormChange}
/>
</Grid>
<Grid item xs={12} sm={6} hidden>
<input
name="image"
type="file"
id="image"
ref={filePathRef}
onChange={handleImageChange}
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
required
fullWidth
label="Last Name"
name="lastName"
value={formData.lastName}
onChange={handleFormChange}
/>
</Grid>
<Grid item xs={12}>
<TextField
required
fullWidth
type="password"
label="Current Password"
name="currentPassword"
value={formData.currentPassword}
onChange={handleFormChange}
/>
</Grid>
<Grid item xs={12}>
<Button type="submit" variant="contained" color="primary">
Save Changes
</Button>
</Grid>
</Grid>
</form>
</Grid>
</Grid>
</Paper>
</Box>
</>
);
};
export default Profile;
后端处理程序:
import type { NextApiRequest, NextApiResponse } from "next";
import { IncomingForm } from "formidable";
export default async function handle(request:NextApiRequest,response:NextApiResponse) {
try {
console.log(JSON.stringify(request.body))
await new IncomingForm().parse(request)
response.status(200).json({b: ""})
} catch (e) {
console.log("error " + e)
response.status(500).json({b: ""})
}
}
export const config = {
Api: {
bodyParser: false,
},
};
我只是想回复但运气不佳。
您不需要
Formidable
来处理 NextJS 13 中的文件,因为它可以开箱即用地处理文件
当您创建新项目时,建议使用
app/
目录。
这里我创建了一个类似的表单,在“/api/home”上提交
const Home = () => {
return (
<form
method="post"
action="/api/home"
style={{ color: "gray" }}
encType="multipart/form-data"
>
<div>
First Name <input type="text" name="firstName" defaultValue="John" />
</div>
<div>
Image <input type="file" name="image" />
</div>
<div>
Last Name <input type="text" name="lastName" defaultValue="Doe" />
</div>
<div>
Current Password{" "}
<input type="password" name="currentPassword" defaultValue="password" />
</div>
<button
type="submit"
style={{ border: "1px solid gray", padding: "4px" }}
>
Submit
</button>
</form>
)
}
export default Home
我们在这里处理表单数据
import path from "path"
import { writeFile } from "fs/promises"
export const POST = async (request: Request) => {
const formData = await request.formData()
// here we are getting form fields
const lastName = formData.get("lastName")
const firstName = formData.get("firstName")
const image = formData.get("image") as File
const currentPassword = formData.get("currentPassword")
let file = {}
// if image is present
if (image?.name) {
// then store the image on local
const fileLocalPath = path.join(process.cwd(), `public/${image.name}`)
const buffer = Buffer.from(await image.arrayBuffer())
await writeFile(fileLocalPath, buffer)
// file information
file = {
size: image.size,
filepath: fileLocalPath,
newFilename: image.name,
type: image.type,
lastModified: image.lastModified,
}
}
return Response.json({ lastName, firstName, image: file, currentPassword })
}
它会给你这样的回应