Я только начал изучать MERN и создал простое приложение, в котором мне нужно добавлять элементы в меню, обновлять и удалять их. для обновления я хочу предварительно заполнить поле ввода данными элемента.
Я сижу над этой проблемой уже много времени, но не могу найти решение. Я установил атрибут значения для каждого ввода, но все равно не вижу никакой информации в поле ввода.
Реагировать на код
MenuItems.jsx
import React, { useEffect, useState } from "react";
import edit from "/edit.png";
import rupee from "../utils/currencyFormatter.jsx";
import api from "../api/api.jsx";
import { capitalize } from "../utils/capitalize.jsx";
import available from "/available.png";
import notavailable from "/notavailable.png";
import deleteImg from "/delete.png";
import EditItem from "./editItem.jsx";
const menuItems = ({ category }) => {
const [editForm, setEditForm] = useState(false);
const [items, setItems] = useState([]);
useEffect(() => {
const getItems = async () => {
try {
const response = await api.get("/menu");
setItems(response.data);
} catch (error) {
console.info(error.message);
}
};
getItems();
}, []);
const [idi, setId] = useState(0);
return (
<ol>
{editForm && (
<EditItem
isVisible = {editForm}
setIsVisible = {setEditForm}
category = {category}
id = {idi}
/>
)}
{items.map((i, index) => (
<li
key = {i._id}
className = "grid grid-cols-6 text-[1.5vw] p-3 transition-all duration-100 hover:bg-orange-400 rounded-md"
>
{index + 1}
<p className = " flex flex-col justify-center font-semibold">
{capitalize(i.item)}
<span className = "font-thin text-[1.3vw]">
{i.description}
</span>
</p>
<span>{rupee.format(i.price)}</span>
<span>
{i.availability ? (
<img
src = {available}
alt = "Available"
className = " h-8 w-8"
/>
) : (
<img
src = {notavailable}
alt = "Not Available"
className = " h-8 w-8"
/>
)}
</span>
<button
onClick = {() => {
setEditForm(true);
setId(i._id);
}}
>
<img src = {edit} alt = "edit" className = "h-10 w-10" />
</button>
<button>
<img
src = {deleteImg}
alt = "delete"
className = " h-10 w-10"
/>
</button>
</li>
))}
</ol>
);
};
export default menuItems;
EditItem.jsx
import React, { useEffect, useRef, useState } from "react";
import axios from "../api/api.jsx";
const editItem = ({ isVisible, setIsVisible, category, id }) => {
const [formData, setFormData] = useState({});
useEffect(() => {
const getItems = async () => {
try {
const response = await axios.get(`/menu/${id}`);
setFormData(response.data);
console.info("updated formData:", formData);
} catch (error) {
console.info(error.message);
setFormData({});
}
};
getItems();
}, [id]);
const handleSubmit = async (event) => {
event.preventDefault();
try {
console.info(formData.category);
const response = await axios.put(`/menu/${id}`, formData);
console.info(response.data);
} catch (error) {
console.error(error.message);
}
setIsVisible(!isVisible);
};
if (!isVisible) return null;
return (
<div className = "fixed inset-0 bg-black bg-opacity-25 backdrop-blur-sm flex justify-center items-center">
<div className = "w-[50%] flex flex-col">
<div className = "bg-white p-2 rounded">
<h2 className = "mb-4 text-2xl text-center font-bold text-gray-900">
Add a new product
</h2>
<form
action = "post"
className = " p-4"
onSubmit = {handleSubmit}
>
<div className = "grid gap-4 sm:grid-cols-2 sm:gap-6">
<div className = "sm:col-span-2">
<label
htmlFor = "item"
className = "block mb-2 text-sm font-medium text-gray-90"
>
Item Name
</label>
<input
type = "text"
name = "item"
id = "item"
className = "bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 "
placeholder = "Type Item name"
required
value = {formData.item}
onChange = {(event) => {
setFormData({
...formData,
item: event.target.value,
});
console.info(
"Item input value:",
event.target.value
);
}}
/>
</div>
<div className = "w-full">
<label
htmlFor = "price"
className = "block mb-2 text-sm font-medium text-gray-90"
>
Price
</label>
<input
type = "number"
name = "price"
id = "price"
className = "bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 "
required
placeholder = "Add the price"
value = {formData.price}
onChange = {(event) =>
setFormData({
...formData,
price: event.target.value,
})
}
/>
</div>
<div>
<label
htmlFor = "category"
className = "block mb-2 text-sm font-medium text-gray-90"
>
Category
</label>
<select
id = "category"
className = "bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5 "
value = {formData.category}
onChange = {(event) => {
setFormData({
...formData,
category: event.target.value,
});
}}
>
<option>Select category</option>
{category.map((c) => (
<option key = {c._id} value = {c._id}>
{c.name}
</option>
))}
</select>
</div>
<div className = "flex items-center">
<label
htmlFor = "availability"
className = "block mb-2 text-sm font-medium text-gray-90 mr-5"
>
Availability
</label>
<input
type = "checkbox"
name = "avaialability"
id = "availability"
value = {formData.availability}
onChange = {(event) => {
if (event.target.checked) {
setFormData({
...formData,
availability: true,
});
}
}}
/>
</div>
<div className = "flex gap-4 items-center">
<label
htmlFor = "veg"
className = "block mb-2 text-sm font-medium text-gray-90"
>
Veg
</label>
<input
type = "radio"
name = "veg_or_nonveg"
value = "veg"
id = "veg"
onChange = {(event) =>
setFormData({
...formData,
veg_or_nonveg: event.target.value,
})
}
/>
<label
htmlFor = "nonveg"
className = "block mb-2 text-sm font-medium text-gray-90"
>
Non Veg
</label>
<input
type = "radio"
name = "veg_or_nonveg"
value = "non-veg"
id = "nonveg"
onChange = {(event) =>
setFormData({
...formData,
veg_or_nonveg: event.target.value,
})
}
/>
</div>
<div className = "sm:col-span-2">
<label
htmlFor = "description"
className = "block mb-2 text-sm font-medium text-gray-90"
>
Description
</label>
<textarea
id = "description"
rows = "8"
className = "block p-2.5 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-primary-500 focus:border-primary-500 "
placeholder = "Item Description"
value = {formData.description}
onChange = {(event) =>
setFormData({
...formData,
description: event.target.value,
})
}
></textarea>
</div>
</div>
<div className = "flex">
<button
type = "submit"
className = "flex items-center px-5 py-2.5 mt-2 text-sm font-medium text-center rounded-lg focus:ring-4 focus:ring-primary-200"
>
Edit product
</button>
<button
className = " flex items-center px-5 py-2.5 mt-2 text-sm font-medium text-center rounded-lg text-red-600 focus:ring-4 focus:ring-primary-200"
onClick = {() => {
setIsVisible(!isVisible);
}}
>
Cancel
</button>
</div>
</form>
</div>
</div>
</div>
);
};
export default editItem;
Экспресс-код
контролеры
import mongoose from "mongoose";
import { menuModel } from "../models/menuModel.js";
export const getMenuItems = async (req, res) => {
try {
const menuItems = await menuModel.find();
res.status(200).json(menuItems);
} catch (err) {
res.status(404).json({ message: err.message });
console.info(err);
}
};
export const getOneItem = async (req, res) => {
const id = req.params.id;
try {
const item = await menuModel.find({ _id: id });
res.status(200).json(item);
} catch (err) {
res.status(404).json({ message: err.message });
}
};
export const addMenuItems = async (req, res) => {
const item = req.body;
const newItem = new menuModel(item);
try {
await newItem.save();
res.status(201).json(newItem);
console.info(newItem);
} catch (err) {
console.info(err);
res.status(409).json({ message: err.message });
}
};
export const updateMenuItmes = async (req, res) => {
const { id: _id } = req.params;
const updatedData = req.body;
try {
if (!mongoose.Types.ObjectId.isValid(_id))
return res.status(404).send("no item with that id exists");
const updates = await menuModel.findByIdAndUpdate(_id, updatedData, {
new: true,
});
res.status(200).json(updates);
} catch (err) {
res.status(409).json({ message: err.message });
}
};
// export const deleteItems = async (req,res) =>{
// }
MenuModel.jsx — содержит модель меню.
import { Decimal128 } from "mongodb";
import mongoose, { model } from "mongoose";
const { Schema } = mongoose;
const menuSchema = new Schema({
item: {
type: String,
required: true,
unique: true,
},
price: {
type: Number,
required: true,
default: 0.0,
},
availability: {
type: Boolean,
required: true,
default: true,
},
veg_or_nonveg: {
type: String,
required: true,
enum: ["Veg", "Non-Veg", "veg", "non-veg"],
},
description: {
type: String,
},
category: [
{
type: Schema.Types.ObjectId,
ref: "categoryModel",
},
],
});
export const menuModel = new model('menuModel', menuSchema);
у меня есть добавленный атрибут значения, как вы можете видеть здесь, но я не нашел предварительно заполненных данных Может ли кто-нибудь помочь мне с этой проблемой.
вот репозиторий GitHub ссылка:
🤔 А знаете ли вы, что...
JavaScript был первоначально создан для улучшения интерактивности веб-страниц.
Похоже, у вас есть вызов getItems() в компоненте editItem, поэтому он снова извлекает те же данные, которые у вас уже были при отображении без редактирования - при условии, что /menu возвращает те же данные для всех элементов, что и /menu/id для одного. Задержка может возникнуть из-за ожидания ответа от базы данных.
Попробуйте передать значения в качестве реквизита компоненту редактирования, чтобы не получать его дважды. Если у вас есть несколько пунктов меню, вы можете сопоставить массив и передать реквизиты каждому отдельному компоненту элемента. а вы пробовали использовать defaultValue
вместо значения для заполнения полей ввода?