I use Next.js latest version. I have a component called “InputMedia”. I use this component 3 times in a page with different props. My problem is: State update is always being done by the first component’s information. Even though I click 3rd component always the first component’s state changes. I tried to send type as a prop, didn’t work. I tried to send important things as arguments didn’t work again.
I alwas played with handleMediaChange function, InputMedia props and InputMedia component.
I will be glad if I can learn what am I missing.
Here is my Page:
"use client";
import Button from "@/components/Button/Button";
import Input from "@/components/Input/Input";
import InputMedia from "@/components/InputMedia/InputMedia";
import Select from "@/components/Select/Select";
import Tab from "@/components/Tab/Tab";
import { useState } from "react";
export default function Manage() {
const [formItems, setFormItems] = useState({
title: "",
description: "",
category: "Psikoloji Testleri",
mainMedia: {},
mainMediaUrl: "",
questions: [
{
questionTitle: "selam",
questionMedia: {},
questionMediaUrl: "",
options: [
{ answer: "", points: [{ resultTitle: "", point: 0, id: "item1" }] },
],
},
],
results: [
{
resultTitle: "",
resultDescription: "",
resultMedia: {},
resultMediaUrl: "",
},
],
});
const [tabIndexStore, setTabIndexStore] = useState({
questionTabIndex: 0,
questionOptionTabIndex: 0,
resultTabIndex: 0,
});
const handleMainPropertiesChange = (e) => {
const { name, value } = e.target;
setFormItems((prev) => ({
...prev,
[name]: value,
}));
};
const handleMediaChange = (e, type, index = null) => {
console.log(type, index, "function");
const { files } = e.target;
if (!files || files.length === 0) return;
const file = files[0];
setFormItems((prev) => {
let updatedItems = { ...prev };
switch (type) {
case "main":
updatedItems.mainMedia = file;
break;
case "question":
if (index !== null && index < updatedItems.questions.length) {
updatedItems.questions[index].questionMedia = file;
}
break;
case "result":
if (index !== null && index < updatedItems.results.length) {
updatedItems.results[index].resultMedia = file;
}
break;
default:
break;
}
return updatedItems;
});
};
const handleQuestionChange = (e, index) => {
const { name, value } = e.target;
const newQuestions = [...formItems.questions];
newQuestions[index][name] = value;
setFormItems((prev) => ({
...prev,
questions: newQuestions,
}));
};
const updateTabIndex = (index, item) => {
setTabIndexStore((prev) => ({
...prev,
[item]: index,
}));
};
return (
<form>
<Input
name="title"
type="text"
handleFunction={handleMainPropertiesChange}
value={formItems.title}
/>
<hr />
<Input
name="description"
type="text"
handleFunction={handleMainPropertiesChange}
value={formItems.description}
/>
<hr />
<Select
name="category"
handleFunction={handleMainPropertiesChange}
value={formItems.category}
/>
<hr />
<InputMedia
media={formItems.mainMedia}
handleMediaChange={(e) => handleMediaChange(e, "main")}
/* handleMediaChange={handleMediaChange}
type="main" */
/>
<hr />
<h1>Questions</h1>
<Tab
items={formItems.questions}
handleFunction={updateTabIndex}
currentIndex={tabIndexStore.questionTabIndex}
itemName="questionTabIndex"
/>
<Input
name="questionTitle"
type="text"
handleFunction={handleQuestionChange}
index={tabIndexStore.questionTabIndex}
value={
formItems.questions[tabIndexStore.questionTabIndex].questionTitle
}
/>
<InputMedia
media={
formItems.questions[tabIndexStore.questionTabIndex].questionMedia
}
handleMediaChange={(e) =>
handleMediaChange(e, "question", tabIndexStore.questionTabIndex)
}
/* handleMediaChange={handleMediaChange}
type="question"
index={tabIndexStore.questionTabIndex} */
/>
<h1>Question Options</h1>
<Tab
items={formItems.questions[tabIndexStore.questionTabIndex].options}
handleFunction={updateTabIndex}
currentIndex={tabIndexStore.questionOptionTabIndex}
itemName="questionOptionTabIndex"
/>
<Input name="option" type="text" />
<Input name="point" type="number" />
<Button type="button" isButtonSecondary={true} name="Add new option" />
<br />
<br />
<Button type="button" isButtonSecondary={true} name="Add new question" />
<hr />
<h1>Results</h1>
<Tab
items={formItems.results}
handleFunction={updateTabIndex}
currentIndex={tabIndexStore.resultTabIndex}
itemName="resultTabIndex"
/>
<Input name="result title" type="text" />
<Input name="result description" type="text" />
<InputMedia
media={formItems.results[tabIndexStore.resultTabIndex].resultMedia}
handleMediaChange={(e) =>
handleMediaChange(e, "result", tabIndexStore.resultTabIndex)
}
/* type="result"
index={tabIndexStore.resultTabIndex} */
/>
<Button type="button" isButtonSecondary={true} name="Add new result" />
<br />
<br />
<Button type="button" isButtonSecondary={false} name="Submit" />
</form>
);
}
{
/* <Input
name="questionMedia"
type="file"
handleFunction={handleQuestionChange}
index={tabIndexStore.questionTabIndex}
value={
formItems.questions[tabIndexStore.questionTabIndex].questionMedia
}
/> */
}
And InputMedia component:
export default function InputMedia({
media,
handleMediaChange,
/* type,
index = null, */
}) {
return (
<>
Media
<label
htmlFor="dropzone-file"
className="flex flex-col items-center justify-center w-full h-64 border-2 border-gray-300 border-dashed rounded-lg cursor-pointer bg-gray-50 dark:hover:bg-bray-800 dark:bg-gray-700 hover:bg-gray-100 dark:border-gray-600 dark:hover:border-gray-500 dark:hover:bg-gray-600"
onClick={(e) => {
e.preventDefault();
console.log("uffufu");
}}
>
<div className="flex flex-col items-center justify-center pt-5 pb-6">
<svg
className="w-8 h-8 mb-4 text-gray-500 dark:text-gray-400"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 20 16"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13 13h3a3 3 0 0 0 0-6h-.025A5.56 5.56 0 0 0 16 6.5 5.5 5.5 0 0 0 5.207 5.021C5.137 5.017 5.071 5 5 5a4 4 0 0 0 0 8h2.167M10 15V6m0 0L8 8m2-2 2 2"
/>
</svg>
<p className="mb-2 text-sm text-gray-500 dark:text-gray-400">
<span className="font-semibold">Click to upload</span> or drag and
drop
</p>
{media instanceof File && (
<p className="text-xs text-gray-500 dark:text-gray-400">
Uploaded media name: {media.name}
</p>
)}
</div>
<input
id="dropzone-file"
type="file"
className="hidden"
onChange={handleMediaChange}
/>
</label>
</>
);
}