#javascript #reactjs
Вопрос:
Я хочу, чтобы в моем блоге была страница архива, которая выглядела бы так (проверьте под заголовком Все статьи по дате) с одним годом вверху, затем месяцем и датой с названием статьи под ним.
У меня есть массив сообщений с типом Meta
, который выглядит так:
export type Meta = {
title: string
date: Date
lastEdited?: Date
description: string
slug: string
tags: Array<Tag>
image?: string
author: string
isPublished?: Boolean
}
И я заставил это работать, но в результате year
оказался рядом, используя:
import React from 'react'
import { getYearMonthDate } from '@/utils/index'
import type { Meta } from '@/types/index'
export const Archive = ({ tutorials }: { tutorials: Meta }) => {
return (
<ul>
{tutorials.map((tutorial: Meta) => {
const [year, month, date] = getYearMonthDate(tutorial.date)
let archiveYear
return (
<li key={tutorial.slug}>
<h3 className="archiveYear">{year}</h3>
<span className="archiveDay">
{month} {date}
</span>
<a className="archiveLink">{tutorial.title}</a>
</li>
)
})}
</ul>
)
}
Я знаю, что мне нужно использовать цикл for и отслеживать старый год, сравнивать его с новым и использовать массив для передачи данных, но это приведет к уродливой HTML-разметке.
Есть ли какой-нибудь способ сделать так, чтобы это выглядело как желаемый результат. Если да, то как мне это сделать?
Комментарии:
1. Я не совсем понял вопрос, но вместо этого использовал hashmap?
Ответ №1:
Я заставил его работать с помощью Map
. Во-первых, я использовал for
цикл и поместил данные своего блога в a Map
в формате year
as key
amp; post[]
as value
.
utils/index.ts
import { format, parseISO, getYear as gY, getDate as gD } from 'date-fns'
export const formatDate = (date: string) => format(parseISO(date), 'MMMM dd, yyyy')
export const getYear = (date: Date) => gY(new Date(date))
export const getMonth = (date: Date) => format(new Date(date), 'MMMM')
export const getDate = (date: Date) => gD(new Date(date))
Архив,tsx
import React from 'react'
import Link from 'next/link'
import { getYear, getMonth, getDate } from '@/utils/index'
import type { Meta } from '@/types/index'
export const Archive = ({
postType,
posts,
}: {
postType: 'essay' | 'tutorial' | 'snippet'
posts: Meta[]
}) => {
const archive = new Map()
for (let i = 0; i < posts.length; i ) {
const post: Meta = posts[i]
const year = getYear(post.date)
if (!archive.has(year)) {
archive.set(year, [post])
} else {
const oldArchive = archive.get(year)
archive.set(year, [...oldArchive, post])
}
}
return (
<ul className="grid grid-cols-[1fr,min(90ch,calc(100%-64px)),1fr] gap-8 archive mb-64">
{Array.from(archive.entries()).map(([archiveYear, posts], i) => {
return (
<li key={i}>
<h3 className="text-3xl font-bold archiveYear">{archiveYear}</h3>
{posts.map((post: Meta) => {
const month = getMonth(post.date)
const date = getDate(post.date)
return (
<div
className="grid grid-cols-[144px,calc(100%-144px)] my-2 text-lg font-medium"
key={post.slug}
>
<span className="text-gray-700 archiveDay dark:text-gray-300">
{month} {date}
</span>
<Link href={`/${postType}/${post.slug}`}>
<a className="text-gray-700 dark:text-gray-300 archiveLink">{post.title}</a>
</Link>
</div>
)
})}
</li>
)
})}
</ul>
)
}