【copy airbnb】1~3 .登录功能\类别\地图功能

1、前言

https://www.bilibili.com/video/BV1ZV4y1S7zB/?spm_id_from=333.337.search-card.all.click&vd_source=12775c50048b2f6e8bece614d77af37e

1、zustand

精悍的状态管理器

2、axios

强大的http请求库

3、query-string

query-string 是一个用于解析和字符串化 URL 查询字符串的库。在处理 URL 查询参数时,它提供了比原生 JavaScript API 更简单和强大的方法。

2、分阶段开发

1、Auth UI

用于生成注册组件以及相关的一系列子组件

  • hooks:使用zustand技术达成状态管理的功能
  • 通讯技术:使用axios技术达成
  • react-hook-form : 用于处理表单功能

2、注册功能、MongoDB、Prisma 设置

  • 安装prisma:npm i -D prisma 
  • 初始化:npx prisma init
    • prisma配置文件:/prisma/schema.prisma
      • 将“datasource db ”下的“provider”的值修改为mongodb
    • 全局配置文件:/.env 记录了数据库的地址

3、登录功能

  • API Route […nextauth].ts:处理认证请求,与社交媒体和数据库交互。
  • schema.prisma:定义数据库模型和关系,与数据库直接互动。
  • getCurrentUser.ts:从 NextAuth.js 检索用户会话数据,使用会话中的电子邮件查询数据库以获取用户详情。

       注意:

  • 社交登录(google、github)是对数据库字段和结构有要求的
  • getCurrentUser.ts中其实是调用了next的next-auth/next库来进行session的获取,背后实际是使用了jwt进行cookie的保存,但是所有逻辑对外不可见罢了
  • nextauth.ts依赖于prisma的查询来实现登录逻辑
  • getCurrentUser.ts依赖于nextauth.ts中的options来进行登录用户信息的获取

4、github登录功能

  • 登录你的github 进入“setting”
  • 进入“Developer setting”
  • 选择“OAth apps”
  • 填写信息,
  • 创建一个秘钥
  • 记住:
  • 在.env中写入:
    • GITHUB_ID=”Ov23limd89i6q7aN1BS2″
      GITHUB_SECRET=”ebc396bd2b43fc1f717ecdac17b82fb2081e20ef”
  • 进入:src/app/components/modals/RegisterModal.tsx
    • import { signIn } from “next-auth/react”;
    • onClick={()=>signIn(“github”)}
    • 设置avatar为github头像时遇到问题

      此时需要配置:next.config.mjs

5、google登录

6、列表创建步骤 1(类别选择)

  • react-hook-form的使用方法
    • watch 用于监听defaultValues中的字段,当字段发生变动时会通知对应的变量,注意:这里变量(category)仍然是string类型,并没有被改造为一个响应式的object类型
    • setValue 用于设置defaultValues中的值,当然你可以设置一些参数来对应更多的功能:
      • shouldDirty:
        • 作用: 如果设置为 true,则会将字段标记为“脏的”。一个“脏的”字段意味着其值已经被用户修改过。
        • 示例: 假设一个表单字段最初的值是 1,然后你使用 setValue 将其值改为 2。如果 shouldDirty 设置为 true,该字段将被标记为“脏的”。
        • 场景:提交按钮状态。某些表单设计中,只有在用户修改了字段后才启用提交按钮。设置为 true 可以使得提交按钮在合适的时候启用。
      • shouldTouch:
        • 作用: 如果设置为 true,则会将字段标记为“已触碰”。一个“已触碰”的字段意味着用户已经与该字段进行过交互(例如,点击或聚焦)。
        • 示例: 即使用户没有手动点击字段,只是通过 setValue 更改了字段的值,如果 shouldTouch 设置为 true,该字段也会被标记为“已触碰”。
        • 场景:表单聚焦。当用户开始填写表单时,可能希望自动聚焦到第一个未触碰过的字段上,以提高填写效率。
      • shouldValidate:
        • 作用: 如果设置为 true,则会触发该字段的验证。即在设置新值之后立即对该字段进行验证。
        • 示例: 如果字段有验证规则(例如,必填项或特定格式),当你通过 setValue 改变字段值并设置 shouldValidate 为 true 时,将立即对该字段进行验证,验证结果会影响 errors 对象。
        • 场景:错误信息更新。如果字段值不符合验证规则,会更新与该字段相关的错误信息,以便及时向用户显示错误提示。

7、列表创建步骤 2(位置选择、地图组件、国家/地区自动完成)

  • 国家和城市列表选择
    • npm install world-countries
import { create } from "zustand";
import countries from "world-countries"
const formattedCountries = countries.map((country)=>({
    value:country.cca2,
    label:country.name.common,
    flag:country.flag,
    latlng:country.latlng,
    region:country.region
}))

const useCountries=()=>{
    const getAll=()=>formattedCountries;
    const getByValue=(value:string)=>{
        return formattedCountries.find((item )=>item.value === value);
    }

    return {
        getAll,
        getByValue
    }
}

export default useCountries;
// const useCountries = create()


// export default useCountries;
  • useCountries
    • 可以看出,world-countries是提供了一个全球国家的列表
    • flag:国旗字符标识 
    • cca2 是 world-countries 数据中每个国家的 Alpha-2 代码(ISO 3166-1 alpha-2),例如美国是 US
    • latlng 是一个数组,包含国家的纬度和经度,例如美国是 [38.0, -97.0]
    • region 是国家所属的地区,例如美国是 Americas
  • 地图搭建
    • npm i leaflet 
    • npm i @types/leaflet 添加类型支持
    • npm i react-leaflet
"use client";
import L, { LatLng, LatLngExpression } from "leaflet";
import { MapContainer, Marker, TileLayer } from "react-leaflet";
import "leaflet/dist/leaflet.css";
import markerIcon2x from "leaflet/dist/images/marker-icon-2x.png";
import markerIcon from "leaflet/dist/images/marker-icon.png";
import markerShadow from "leaflet/dist/images/marker-shadow.png";

// @ts-ignore
delete L.Icon.Default.prototype._getIconUrl;
L.Icon.Default.mergeOptions({
  iconUrl: markerIcon.src,
  iconRetinaUrl: markerIcon2x.src,
  shadowUrl: markerShadow.src,
});

interface MapProps {
  center?: number[];
}

const Map: React.FC<MapProps> = ({ center }) => {
  return (
    <MapContainer
      center={(center as LatLngExpression) || [51, -0.09]}
      zoom={center ? 4 : 2}
      scrollWheelZoom={false}
      className="h-[35vh] rounded-lg"
    >
      <TileLayer
        attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
      ></TileLayer>

      {center && (
        <Marker position={center as L.LatLngExpression}></Marker>
      )}
    </MapContainer>
  );
};
export default Map;

发表评论

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

滚动至顶部