当前位置: 首页 > wzjs >正文

做网站怎么投放广告外贸网站模板

做网站怎么投放广告,外贸网站模板,大连电子学校网站建设,富士康做电商网站current branch 对应如下文档 redis ioredis 本专栏内容均可在Github:notes_02 找到 完整项目使用技术栈: Nextjs15 MySQL Redis Auth Prisma i18n strapi Docker vercel 一、本节目标 实现笔记列表展开回收和 Suspense 的实践 二、修改根…

current branch 对应如下文档

redis

ioredis

本专栏内容均可在Github:notes_02 找到

完整项目使用技术栈:
Nextjs15 + MySQL + Redis + Auth + Prisma + i18n + strapi + Docker + vercel

一、本节目标

实现笔记列表展开回收和 Suspense 的实践

在这里插入图片描述

二、修改根布局和其他页面

修改 app/components/SidebarNoteList.tsx:

import SidebarNoteItem from "@/components/SidebarNoteItem";export default async function NoteList({ notes }) {const arr = Object.entries(notes);if (arr.length == 0) {return <div className="notes-empty">{"No notes created yet!"}</div>;}return (<ul className="notes-list">{arr.map(([noteId, note]) => {return (<li key={noteId}><SidebarNoteItem noteId={noteId} note={JSON.parse(note)} /></li>);})}</ul>);
}

这里我们将具体的每条笔记抽离成单独的 SidebarNoteItem 组件,

app/components/SidebarNoteItem.tsx 代码如下:

import dayjs from "dayjs";
import SidebarNoteItemContent from "@/components/SidebarNoteItemContent";export default function SidebarNoteItem({ noteId, note }) {const { title, content = "", updateTime } = note;return (<SidebarNoteItemContentid={noteId}title={note.title}expandedChildren={<p className="sidebar-note-excerpt">{content.substring(0, 20) || <i>(No content)</i>}</p>}><header className="sidebar-note-header"><strong>{title}</strong><small>{dayjs(updateTime).format("YYYY-MM-DD hh:mm:ss")}</small></header></SidebarNoteItemContent>);
}

这里我们又抽离了一个 SidebarNoteItemContent 组件,用来实现展开和收回功能,我们将笔记的标题和时间的 JSX 作为 children 传递给了 SidebarNoteItemContent

app/components/SidebarNoteItemContent.tsx 代码如下:

"use client";import { useState, useRef, useEffect, useTransition } from "react";
import { useRouter, usePathname } from "next/navigation";export default function SidebarNoteContent({id,title,children,expandedChildren,
}) {const router = useRouter();const pathname = usePathname();const selectedId = pathname?.split("/")[1] || null;const [isPending] = useTransition();const [isExpanded, setIsExpanded] = useState(false);const isActive = id === selectedId;// Animate after title is edited.const itemRef = useRef(null);const prevTitleRef = useRef(title);useEffect(() => {if (title !== prevTitleRef.current) {prevTitleRef.current = title;itemRef.current.classList.add("flash");}}, [title]);return (<divref={itemRef}onAnimationEnd={() => {itemRef.current.classList.remove("flash");}}className={["sidebar-note-list-item",isExpanded ? "note-expanded" : "",].join(" ")}>{children}<buttonclassName="sidebar-note-open"style={{backgroundColor: isPending? "var(--gray-80)": isActive? "var(--tertiary-blue)": "",border: isActive? "1px solid var(--primary-border)": "1px solid transparent",}}onClick={() => {const sidebarToggle = document.getElementById("sidebar-toggle");if (sidebarToggle) {sidebarToggle.checked = true;}router.push(`/note/${id}`);}}>Open note for preview</button><buttonclassName="sidebar-note-toggle-expand"onClick={(e) => {e.stopPropagation();setIsExpanded(!isExpanded);}}>{isExpanded ? (<imgsrc="/chevron-down.svg"width="10px"height="10px"alt="Collapse"/>) : (<img src="/chevron-up.svg" width="10px" height="10px" alt="Expand" />)}</button>{isExpanded && expandedChildren}</div>);
}

这里 SidebarNoteItemContent 具体的实现其实并不重要,你只要知道这是一个客户端组件就行了。在这个客户端组件里我们用了 useState 来控制展开和收回的状态,然后添加了一些动画效果,仅此而已。如果步骤正确的话,此时的页面效果为:

在这里插入图片描述

这个时候你可能会有个疑问:为什么要这样做呢?为什么不直接把 SidebarNoteItem 声明为客户端组件,然后直接在这个组件里全部实现呢?还要用传递 children 这么复杂的方式?

考验你是否认真学习了之前的知识到了!

在这段代码中,SidebarNoteItem 是一个服务端组件,在这个组件中我们引入了 dayjs 这个库,然而我们却是在 SidebarNoteItemContent 这个客户端组件中使用的 dayjs。请问最终客户端的 bundle 中是否会打包 dayjs 这个库?

在这里插入图片描述

答案是不会。在服务端组件中使用 JSX 作为传递给客户端组件的 propJSX 会先进行服务端组件渲染,再发送到客户端组件中。也就是说,发送给客户端组件的并不是:

<header className="sidebar-note-header"><strong>{title}</strong><small>{dayjs(updateTime).format("YYYY-MM-DD hh:mm:ss")}</small>
</header>

而是编译后的如:

<header class="sidebar-note-header"><strong>ea molestias</strong><small>2023-12-13 05:19:48</small>
</header>

三、使用 Suspense 实现骨架图的效果

在这里插入图片描述

因为我们现在将笔记列表数据的获取放在了顶层,所以直接为 SidebarNoteList 添加 Suspense 是没有效果的,我们需要将数据获取改为在 SidebarNoteList 组件内部。

修改 app/components/Sidebar.tsx 代码如下:

import React, { Suspense } from "react";
import Link from "next/link";
import SidebarNoteList from "../components/SidebarNoteList";
import EditButton from "./EditButton";
import NoteListSkeleton from "./NoteListSkeleton";export default async function Sidebar() {return (<><section className="col sidebar"><Link href={"/"} className="link--unstyled"><section className="sidebar-header"><imgclassName="logo"src="/favicon.ico"width="22px"height="20px"alt=""role="presentation"/><strong>React Notes</strong></section></Link><section className="sidebar-menu" role="menubar"><EditButton noteId={null}>New</EditButton></section><nav><Suspense fallback={<NoteListSkeleton />}><SidebarNoteList /></Suspense></nav></section></>);
}

添加 app/components/NoteListSkeleton.tsx,代码如下:

export default function NoteListSkeleton() {return (<div><ul className="notes-list skeleton-container"><li className="v-stack"><divclassName="sidebar-note-list-item skeleton"style={{ height: "5em" }}/></li><li className="v-stack"><divclassName="sidebar-note-list-item skeleton"style={{ height: "5em" }}/></li><li className="v-stack"><divclassName="sidebar-note-list-item skeleton"style={{ height: "5em" }}/></li></ul></div>);
}

app/components/SidebarNoteList.tsx 代码如下,为了让效果更加明显,我们添加了一个 sleep 函数:

import SidebarNoteItem from "../components/SidebarNoteItem";
import { getAllNotes } from "@/lib/redis";export default async function NoteList() {const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));await sleep(1000);const notes = await getAllNotes();const arr = Object.entries(notes);if (arr.length == 0) {return <div className="notes-empty">{"No notes created yet!"}</div>;}return (<ul className="notes-list">{arr.map(([noteId, note]) => {return (<li key={noteId}><SidebarNoteItem noteId={noteId} note={JSON.parse(note)} /></li>);})}</ul>);
}

此时页面效果如下:

在这里插入图片描述

那么问题来了,SidebarNoteListSuspense 和不用 Suspense,具体有什么改变呢?

我们把 sleep 的时间设置为 3s。这是不使用 Suspense 的效果,我们从 github 主页输入地址 http://localhost:3000/:

在这里插入图片描述

输入地址后,我们等待了大概 3s 后,页面突然完全展现。

这是使用 Suspense 的效果,我们还是从github 主页输入地址 http://localhost:3000/:

在这里插入图片描述

我们可以看到,使用 Suspense,数据加载不会阻塞页面,也就是说在笔记列表还在加载的时候,用户依然可以与页面其他部分进行交互,比如点击 New 按钮新建笔记。

http://www.dtcms.com/wzjs/96161.html

相关文章:

  • 在线做c语言题目的网站哪有免费的网站
  • 广州有哪些做网站的公司字节跳动广告代理商加盟
  • 论坛网站html模板网站关键词在哪里看
  • 微信订阅号做微网站吗浏览器下载大全
  • 中山做网站哪个公司好seo优化代理
  • 怎么做属于自己的售卡网站seo关键词排名优化
  • 什么网站可以做国外批发网东台网络推广
  • b站视频推广费用一般多少做seo推广一年大概的费用
  • 网站 微信小程序怎么做宁波seo推荐推广平台
  • 网站特色栏目重要性东莞网络推广托管
  • 西安做网站首选搜索引擎优化技术都有哪些
  • 网站广告条幅怎么做动态的湖南发展最新消息公告
  • 如何做企业介绍seo常规优化
  • 常德小程序开发公司网站seo查询工具
  • 一般云主机可以做视频网站吗优化网站找哪家
  • 网站建设与优化推广方案四川seo快速排名
  • 给公司网站设计免费的黄冈网站代码
  • php开源企业网站系统推广网站都有哪些
  • 网站建设公司特点网站推广软件下载
  • 安徽建设工程信息网新网站哪儿登陆日本进口yamawa
  • 为什么做民宿网站百度推广中心
  • 郑州做营销型网站公司在线培训app
  • 做外贸生意最好的网站深圳seo优化排名
  • 做爰网站下载seo网络营销公司
  • wordpress登陆后查看成都关键词优化报价
  • 网站建设托管公司营销型网站的分类不包含
  • 优酷网站建设视频教程集优化教程
  • 兰州做网站哪家专业南京百度网站推广
  • 如何引导企业老板做网站百度url提交
  • 长沙企业建站销售电话软件推广是什么工作