[copy airbnb] 6. 使用服务器组件获取列表

1、可选链操作符

可选链操作符是es2020(ES11)引入的新特性,可以安全的使用嵌套对象的某些属性,即使这些属性未定义(undefined)或者为空(null),也不会报错。

//onAction?.(actionId) 的意思是,如果 onAction 是一个函数,则调用这个函数并传递 actionId 作为参数。如果 onAction 为 null 或 undefined,则表达式求值为 undefined,且不会尝试调用函数(从而避免了可能的错误)。
onAction?.(actionId);

2、date-fns

date-fns 是一个现代的JavaScript日期实用程序库,它提供了最全面、简单和一致的工具集,用于在浏览器和Node.js中操纵JavaScript日期。date-fns 是不可变和纯粹的——它使用纯函数构建,并且总是返回一个新的日期实例而不是改变传递的那一个,这有助于防止错误。

您可以通过访问官方网站来了解更多信息,或者通过访问其NPM包页面来查看如何在项目中开始使用date-fns。如果你需要具体的关于如何使用date-fns来格式化日期的例子,可以查看如Stack Overflow上的指导

此外,date-fns还为在UTC而非系统时区中执行计算提供了工具,这可以通过date-fns/utc来实现。如果您需要处理时区问题,date-fns还提供了一个专门的包date-fns-tz

  • npm install date-fns
  • 在 date-fns 库中,format 函数用于将日期格式化为字符串。”PP” 是 format 函数的一个格式字符串选项,用来指定输出日期的格式。
    • P 代表日期,例如:01/31/2020 (美式格式,月/日/年),对应不同的地区会按照当地习惯显示。
    • PP会在P的基础上加上日期的名字,如:Jan 31st, 2020。
import { format } from 'date-fns';

const start = new Date();
const formattedDate = format(start, "PP");

console.log(formattedDate);

3、主要代码

"use client";

import { Listing, Reservation } from "@prisma/client";
import { SafeUser } from "@/app/types";
import { useRouter } from "next/navigation";
import useCountries from "@/app/hooks/useCountries";
import { useCallback, useMemo } from "react";
import { format } from "date-fns";
import Image from "next/image";
import HeartButton from "../HeartButton";
import Button from "../Button";

interface ListingCardProp {
  data: Listing;
  reservation?: Reservation;
  onAction?: (id: string) => void;
  disabled?: boolean;
  actionLabel?: string;
  actionId?: string;
  currentUser: SafeUser | null;
}

const ListingCard: React.FC<ListingCardProp> = ({
  data,
  reservation,
  onAction,
  disabled,
  actionLabel,
  actionId = "",
  currentUser,
}) => {
  const router = useRouter();
  const { getByValue } = useCountries();
  const location = getByValue(data.locationValue);
  const handleCancel = useCallback(
    (e: React.MouseEvent<HTMLButtonElement>) => {
      e.stopPropagation();
      if (disabled) {
        return;
      }

      onAction?.(actionId);
    },
    [onAction, actionId, disabled]
  );

  const price = useMemo(() => {
    if (reservation) {
      return reservation.totalPrice;
    }

    return data.price;
  }, [reservation, data]);

  const reservationDate = useMemo(() => {
    if (!reservation) {
      return null;
    }

    const start = new Date(reservation.startDate);
    const end = new Date(reservation.endDate);

    return `${format(start, "PP")} - ${format(end, "PP")}`;
  }, [reservation]);
  return (
    <div
      onClick={() => router.push(`/listings/${data.id}`)}
      className="col-span-1 cursor-pointer group"
    >
      <div className="flex flex-col gap-2 w-full">
        <div className=" aspect-square w-full relative overflow-hidden rounded-xl">
          <Image
            fill
            alt="listing"
            src={data.imageSrc}
            className="object-cover h-full w-full group-hover:scale-110 transition"
          ></Image>
          <div className="absolute top-3 right-3"> 
            <HeartButton
                listingId={data.id}
                currentUser={currentUser}
            ></HeartButton>
          </div>
        </div>
        <div className="font-semibold text-lg">
            {location?.region},{location?.label}
        </div>
        <div className="font-light text-neutral-500">
            {reservationDate || data.category}
        </div>
        <div className="flex flex-row items-center gap-1">
            <div className="font-semibold">
                $ {price}
            </div>
        </div>
        {!reservation && (
            <div className="font-light">night</div>
        )}
      </div>
      {onAction && actionLabel && (
        <Button
            disabled={disabled}
            small
            label={actionLabel}
            onClick={handleCancel}
        ></Button>
      )}
    </div>
  );
};
export default ListingCard;

4、”use client”

在 Next.js 中,是否在前端还是后端运行取决于是否使用了 "use client" 指令以及代码所在的位置。我们来详细解释一下这两个概念以及它们的应用。

“use client” 指令

  • “use client” 指令用于指示模块应在客户端运行。默认情况下,Next.js 中的页面和组件是服务器端渲染的(SSR),除非明确使用 "use client" 指令。
  • 客户端组件:当一个文件以 "use client" 开头时,该文件中的所有代码都会在客户端运行。这对于需要在客户端执行的代码,例如事件处理、状态管理等,是必要的。

服务器端渲染 (SSR) 与客户端渲染 (CSR)

  • 服务器端渲染 (SSR):页面在服务器端生成 HTML,然后将 HTML 发送到客户端。这可以提高初次加载的速度,并改善 SEO,因为搜索引擎可以索引服务器端生成的内容。
  • 客户端渲染 (CSR):页面在客户端生成 HTML,通常是通过 JavaScript。在页面加载时,客户端会执行 JavaScript 代码来生成和显示内容。

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部