React - Условия в Map отрабатывают не так, как я ожидал
С бэка мне приходит массив объектов в таком виде:
0: {_id: '6149ed683444e100fa6830b5', user: '61487ece544179033653eac5', date: '2021-09-03T00:00:00.000Z', time: '2', __v: 0}
1: {_id: '614ad40b9643c003b3222ef3', user: '61487ece544179033653eac5', date: '2021-09-07T00:00:00.000Z', time: '3', __v: 0}
2: {_id: '614ae776890fa8046b12ead9', user: '61487ece544179033653eac5', date: '2021-09-04T00:00:00.000Z', time: '2', __v: 0}
3: {_id: '614aeb79890fa8046b12eb7b', user: '61487ece544179033653eac5', date: '2021-09-13T00:00:00.000Z', time: '1', __v: 0}
4: {_id: '614aefbe890fa8046b12ec01', user: '61487ece544179033653eac5', date: '2021-09-05T00:00:00.000Z', time: '4', __v: 0}
5: {_id: '614b195fc80ddd0b8b230d8b', user: '61487ece544179033653eac5', date: '2021-09-23T00:00:00.000Z', time: '3', __v: 0}
6: {_id: '614b52ed1b973001155b6380', user: '61487ece544179033653eac5', date: '2021-09-08T00:00:00.000Z', time: '3', __v: 0}
7: {_id: '614b53311b973001155b63a5', user: '61487ece544179033653eac5', date: '2021-09-09T00:00:00.000Z', time: '3', __v: 0}
Я пробегаюсь по этом массиву объектов таким образом с помощью map:
{store.time.map((time, indx) => (
<>
{time.time && time.date === dayOfMonth ? (
<div className="flex items-center edit h-10 bg-custom-orange justify-center text-white rounded-sm">
<div className="text-2xl">{time.time} ч.</div>
<div className="ml-3 cursor-pointer hover:opacity-90">
<svg
width="15"
height="15"
viewBox="0 0 19 19"
fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
d="M2.375 13.6562V16.625H5.34375L14.0996 7.86916L11.1308 4.90041L2.375 13.6562ZM16.3954 5.57333C16.7042 5.26458 16.7042 4.76583 16.3954 4.45708L14.5429 2.60458C14.2342 2.29583 13.7354 2.29583 13.4267 2.60458L11.9779 4.05333L14.9467 7.02208L16.3954 5.57333Z"
fill="#fff"
/>
</svg>
</div>
</div>
) : (
<div className="flex">
<input
type="text"
onChange={(e) => onChange(e)}
className="flex items-center justify-center w-10 h-10 rounded-md mr-2 max-w-10 max-h-10 text-md time-input"
/>
<div onClick={() => sendTime(user._id)} className="cursor-pointer hover:opacity-90">
<svg
width="40"
height="40"
viewBox="0 0 60 60"
fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
d="M53.3333 0H6.66667C2.96667 0 0 3 0 6.66667V53.3333C0 57 2.96667 60 6.66667 60H53.3333C57 60 60 57 60 53.3333V6.66667C60 3 57 0 53.3333 0ZM46.6667 33.3333H33.3333V46.6667H26.6667V33.3333H13.3333V26.6667H26.6667V13.3333H33.3333V26.6667H46.6667V33.3333Z"
fill="#86C443"
/>
</svg>
</div>
</div>
)}
</>
))}
Условие звучит так:
- если в этом объекте есть время и дата этого объекта совпадает с датой в таблице -> отобрази мне этот элемент заполненным, если нет -> отобрази пустой инпут. Но проблема в том, что сравнивается каждый объект в массиве с каждой датой из таблицы, и на выходе я получаю следующее:

Ожидаю же я увидеть такой результат:

Таблица чисел месяца формируется отдельно от таблицы с датами. На сервере это выглядит так:
async generateDate() {
const value = moment();
const startDay = value.clone().startOf("month").startOf("week");
const endDay = value.clone().endOf("month").endOf("week");
const day = startDay.clone().subtract(-4, "day");
const calendar = [];
while (day.isBefore(endDay, "day")) {
calendar.push(
Array(1)
.fill(0)
.map(() => day.add(1, "day").clone()),
);
}
return calendar;
}
На клиенте так:
{store.calendar.map((week: any) => (
<li className="mr-4">
{week.map((day: any) => (
<div className="flex">
<div className="text-2xl w-10 h-10 p-4 flex items-center justify-center">
{moment(day).format("D").toString()}
</div>
</div>
))}
</li>
В голову приходят только костыльные решения с display none. Но мне почему-то кажется есть более правильный способ решить эту проблему. Заранее благодарен за помощь в этом вопросе!
Ответы (2 шт):
Когда мы проходим map в Reacte мы всегда должны указывать key для элементов. Я не уверен что это до конца решит проблему. Ключи помогают React определять, какие элементы были изменены, добавлены или удалены. Их необходимо указывать, чтобы React мог сопоставлять элементы массива с течением времени:
const numbers = [1, 2, 3, 4, 5]; const listItems = numbers.map((number) => {number} );
const data = [
{
"_id": "614ed395ae139cd283c04b77",
"user": "05213607-0456-48af-b611-5758ef62098d",
"date": "2021-09-26",
"time": 0
},
{
"_id": "614ed395b026737708dbf328",
"user": "de9f26a6-ee0a-42d0-8d84-7b93073330fc",
"date": "2021-09-29",
"time": 2
},
{
"_id": "614ed395deca8f0b84f63a33",
"user": "ca5017e3-85e5-412b-a468-59cd0bca960b",
"date": "2021-09-30",
"time": 2
},
{
"_id": "614ed395dae3c5efde6f9721",
"user": "f68459ca-27c6-4f4e-9334-8845f82012a8",
"date": "2021-09-28",
"time": 6
},
{
"_id": "614ed3950a0b5db824a537f2",
"user": "7840b774-e604-4d9b-8f8b-da7ce782ecab",
"date": "2021-09-26",
"time": 2
},
{
"_id": "614ed395b4bba2149ec12f78",
"user": "6a5895d4-2649-4e5f-936f-05e6ec7a0a42",
"date": "2021-09-30",
"time": 6
}
];
const date = [];
// сформируем массив дат
for (let i = 1; i <= 30; i++){
date.push({
date: `2021-09-${i}`
});
}
//объединили два массива по датам.
date.map((value) => {
const find = data.filter(item => value.date == item.date);
value.list = find;
});
console.log(date);
Из примера видно, что мы получаем один массив со всеми необходимыми данными, которые объединены по дате. Соответственно, теперь куда легче сделать вывод этой информации.
Если у нас в объекте массив list пустой, то отрисовывай плюс (добавление).
Если у нас массив list имеет значения, то отрисовываем их.