I've mapped an array of objects to a div
. I would like to change background color of the selected div in getNext12MonthsWithYear
map function with useState
. Currently on click, background color of all div
s is changing, however I want to change only the selected div
's background color. Here is what I have done so far :
import React, { useState } from "react";
const Test = () => {
const [monthSelected, setMonthSelected] = useState(false);
const selectMonth = (id) => {
monthSelected ? setMonthSelected(false) : setMonthSelected(true);
console.log(id);
};
function getNext12MonthsWithYear() {
var now = new Date();
var month = now.getMonth();
var year = now.getFullYear();
var names = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
var res = [];
for (var i = 0; i < 12; i) {
res.push({ month: names[month] " " year, status: -1 });
if ( month === 12) {
month = 0;
year;
}
}
return res;
}
let upcomingMonths = getNext12MonthsWithYear();
// console.log(upcomingMonths);
return (
<div style={{ display: "flex", flexDirection: "row" }}>
{upcomingMonths.map((upcomingMonth, id) => {
return (
<div
key={id}
id={id}
onClick={() => selectMonth(id)}
style={{
width: "50px",
height: "50px",
border: "1px solid black",
backgroundColor: monthSelected ? "green" : "white",
}}
>
{upcomingMonth.month}
</div>
);
})}
</div>
);
};
export default Test;
CodePudding user response:
Create a separate component for looping element. Complete code here
import { useState } from "react";
const NewCom = ({ id, upcomingMonth }) => {
const [monthSelected, setMonthSelected] = useState(false);
const selectMonth = (id) => {
monthSelected ? setMonthSelected(false) : setMonthSelected(true);
console.log(id);
};
return (
<div
id={id}
onClick={() => selectMonth(id)}
style={{
width: "50px",
height: "50px",
border: "1px solid black",
backgroundColor: monthSelected ? "green" : "white",
}}
>
{upcomingMonth.month}
</div>
);
};
const Test = () => {
function getNext12MonthsWithYear() {
var now = new Date();
var month = now.getMonth();
var year = now.getFullYear();
var names = [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
];
var res = [];
for (var i = 0; i < 12; i) {
res.push({ month: names[month] " " year, status: -1 });
if ( month === 12) {
month = 0;
year;
}
}
return res;
}
let upcomingMonths = getNext12MonthsWithYear();
console.log(upcomingMonths);
return (
<div style={{ display: "flex", flexDirection: "row" }}>
{upcomingMonths.map((upcomingMonth, id) => (
<NewCom key={id} id={id} upcomingMonth={upcomingMonth} />
))}
</div>
);
};
export default Test;
CodePudding user response:
Instead of having a boolean in state, you can store the id of selected month
const [monthSelected, setMonthSelected] = useState(null);
And while rendering the list set the id as monthSelected
directly
<div
key={id}
id={id}
onClick={() => setMonthSelected(id)}
style={{
width: "50px",
height: "50px",
border: "1px solid black",
backgroundColor: monthSelected === id ? "green" : "white",
}}
>
{upcomingMonth.month}
</div>
CodePudding user response:
I change useState to number:
const [monthSelected, setMonthSelected] = useState(null);
And compare current monthSelected with id:
backgroundColor: monthSelected === id ? "green" : "white"
Full solution:
import React, { useState } from "react";
const Test = () => {
const [monthSelected, setMonthSelected] = useState(null);
function getNext12MonthsWithYear() {
var now = new Date();
var month = now.getMonth();
var year = now.getFullYear();
var names = [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
];
var res = [];
for (var i = 0; i < 12; i) {
res.push({ month: names[month] " " year, status: -1 });
if ( month === 12) {
month = 0;
year;
}
}
return res;
}
let upcomingMonths = getNext12MonthsWithYear();
// console.log(upcomingMonths);
return (
<div style={{ display: "flex", flexDirection: "row" }}>
{upcomingMonths.map((upcomingMonth, id) => {
return (
<div
key={id}
id={id}
onClick={() => setMonthSelected(id)}
style={{
width: "50px",
height: "50px",
border: "1px solid black",
backgroundColor: monthSelected === id ? "green" : "white"
}}
>
{upcomingMonth.month}
</div>
);
})}
</div>
);
};
export default Test;
CodePudding user response:
You need to pass the id to the state to let your component know which is the current selected element. Right now, you have a boolean state which, if set to true, changes color of all the months. Try changing your code to the below code.
import React, { useState } from "react";
const Test = () => {
const [monthSelected, setMonthSelected] = useState(false);
const selectMonth = (id) => {
setSelectedMonth(id)
};
function getNext12MonthsWithYear() {
var now = new Date();
var month = now.getMonth();
var year = now.getFullYear();
var names = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
var res = [];
for (var i = 0; i < 12; i) {
res.push({ month: names[month] " " year, status: -1 });
if ( month === 12) {
month = 0;
year;
}
}
return res;
}
let upcomingMonths = getNext12MonthsWithYear();
// console.log(upcomingMonths);
return (
<div style={{ display: "flex", flexDirection: "row" }}>
{upcomingMonths.map((upcomingMonth, id) => {
return (
<div
key={id}
id={id}
onClick={() => selectMonth(id)}
style={{
width: "50px",
height: "50px",
border: "1px solid black",
backgroundColor: id===monthSelected ? "green" : "white",
}}
>
{upcomingMonth.month}
</div>
);
})}
</div>
);
};
export default Test;
Alternatively, if you want to allow selecting multiple months, you would need to have as many states as there are months (12).