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

交互式网站如何做wordpress缩略图只生成full

交互式网站如何做,wordpress缩略图只生成full,wordpress文档内容页,什么网站做禽苗的多Next.js 实战笔记 2.0:深入 App Router 高阶特性与布局解构 上一篇笔记: Next.js 实战笔记 1.0:架构重构与 App Router 核心机制详解 上篇笔记主要回顾了一些 Next12 到 Next15 的一些变化,这里继续学习/复习一些已有或者是新的…

Next.js 实战笔记 2.0:深入 App Router 高阶特性与布局解构

上一篇笔记:

  • Next.js 实战笔记 1.0:架构重构与 App Router 核心机制详解

上篇笔记主要回顾了一些 Next12 到 Next15 的一些变化,这里继续学习/复习一些已有或者是新的变化

turbo 的补充

在实际运行的过程当中,我发现使用 yarn dev --turbo 运行,编译并不稳定——不确定是因为我的 Mac 还是 intel 的原因,毕竟现在很多的优化都是针对 M 芯片做的,总之目前还是 fallback 到了默认的开发模式……

其他保留页面

除了 page.jslayout.js 之外,NextJS 还有其他两个保留页面

报错页面

也就是 error.js,大体的实现如下:

"use client";
import React from "react";const MealsErrorPage = () => {return (<main className="error"><h1>An Error Occurred!</h1><p>Fail to fetch meal data. Please try again later.</p></main>);
};export default MealsErrorPage;

需要注意的是, error.js 必须要使用 use client,因为这个页面即会处理 server end 的异常,也会处理 client end 的异常

它的作用与 layout 类似,在当前/兄弟姐妹/子页面出现异常后,会渲染当前页面

not found

大体实现如下:

import React from "react";const NotFoundPage = () => {return (<main className="not-found"><h1>Not Found</h1><p>Could not find the page you are looking for.</p></main>);
};export default NotFoundPage;

error.js 类似,不过在组件内调用 notFound(); 也可以重定向到当前页面

表单

其实这部分不完全是 NextJS 的内容,更多的是 React 19 提出的新功能。这里会基于 NextJS 中的实现进行讨论,React 的话,等到 NextJS 的内容过完了后,重新过一遍 React18 和 19 的新特性

提交表单

之前在使用 React 的表单时,提交事件其实不由 action 触发,而是通过 onClick + preventDefault() 可以绕过 action 进行实现。不过目前 NextJS 目前则可以直接通过 action 在 server end 完成表单的提交,并且将表单中有的数据包成 formData 作为参数

下面是一个简单的实现:

export default function ShareMealPage() {const shareMeal = async (formData) => {// use server must be an async function"use server";const meal = {creator: formData.get("name"),creator_email: formData.get("email"),title: formData.get("title"),summary: formData.get("summary"),instructions: formData.get("instructions"),image: formData.get("image"),};console.log(meal);};return (<><header className={classes.header}><h1>Share your <span className={classes.highlight}>favorite meal</span></h1><p>Or any other meal you feel needs sharing!</p></header><main className={classes.main}><form className={classes.form} action={shareMeal}></form></main></>);
}

服务端输出的结果:

这里需要注意的是,如果组件本身使用了 use client,那么在方法内使用 use server 就会报错……

useFormStatus

这里简单的提一下使用方法,就是一个返回的 pending 可以更灵活的运用

const { pending, data, method, action } = useFormStatus();

具体的使用案例如下:

"use client";import React from "react";
import { useFormStatus } from "react-dom";const MealsFormSubmit = () => {const { pending } = useFormStatus();return (<button disabled={pending}>{pending ? "Submitting" : "Share Meal"}</button>);
};export default MealsFormSubmit;

我这里是单独拆了一个组件出来使用,这个方法和官方提供的使用方法类似:

import { useFormStatus } from "react-dom";
import action from "./actions";function Submit() {const status = useFormStatus();return <button disabled={status.pending}>Submit</button>;
}export default function App() {return (<form action={action}><Submit /></form>);
}

具体的操作,React 在内部已经实现了,只要通过 action 进行触发,就可以顺利地监听到表单的状态变化

useFormState

目前 React 官方是把 useFormState 重命名成了 useActionState,并且用法是一样的——除了后者是从 react 中导入,前者是 react-dom 中导入:

In earlier React Canary versions, this API was part of React DOM and called useFormState.

但是我看了下,不知道为啥用 useActionState 会报错,用 useFormState 暂时没问题。介于我用的这个版本,useFormState 还没有被移除,因此暂时就使用了 useFormState

hook 的 signature 如下:

const [state, formAction, isPending] = useActionState(fn, initialState, permalink?);

同理,因为是 hook,所以也需要使用 use client

具体使用方法如下:

"use client";import ImagePicker from "@/components/meals/image-picker";
import classes from "./page.module.css";
import { shareMeal } from "@/lib/action";
import MealsFormSubmit from "@/components/meals/meals-form-submit";
import { useFormState } from "react-dom";export default function ShareMealPage() {const [state, formAction] = useFormState(shareMeal, { message: null });return (<><header className={classes.header}><h1>Share your <span className={classes.highlight}>favorite meal</span></h1><p>Or any other meal you feel needs sharing!</p></header><main className={classes.main}><form className={classes.form} action={formAction}><p className={classes.actions}>{state.message && <p>{state.message}</p>}</p></form></main></>);
}

shareMeal 的实现如下:

export const shareMeal = async (prevState, formData) => {const meal = {creator: formData.get("name"),creator_email: formData.get("email"),title: formData.get("title"),summary: formData.get("summary"),instructions: formData.get("instructions"),image: formData.get("image"),};if (isInvalidText(meal.title) ||isInvalidText(meal.summary) ||isInvalidText(meal.instructions) ||isValidEmail(meal.creator_email) ||isValidEmail(meal.creator) ||!meal.creator_email.includes("@") ||!meal.image ||meal.image.size === 0) {return {message: "Invalid input",};}await saveMeal(meal);redirect("/meals/");
};

这部分其实没什么特别好深入挖掘的,使用方法和官方文档基本一致,属于跟着官方文档实现就好了,大体需要注意的地方有:

  • form 的 action 需要使用 useFormState 返回的第二个值,这样方便 React 进行监听
  • 原本的 action fn 第一个参数需要接受 initialState 作为第一个参数

💡:我个人觉得,将 useFormStateuseFormStatus 封装成一个通用的 custom hook,保证全局的 initialState 一致,这样处理起来可能会更加的高效,也可以更好地减少 boilerplate 代码

缓存

这部分主要是使用 revalidatePath() 这个方法,在进行重定向的时候,去清除 NextJS 中存在的缓存

说实话,这部分的内容可能真的是要多做一点 deploy 之后,才有更多的感觉。目前我有一个小项目是通过 NextJS+github actions 部署到 GH Pages 上的,我只能说似乎是因为 use client 的关系,页面还是会零零碎碎的去 fetch 一些小的 JS 文件。只不过因为页面整体的内容比较少,加载速度还是比较快——大概在 100-200ms 之间,因此目前我还没有花太多的时间和心力去研究 deploy 这部分的内容

dynamic metadata

metadata 的内容在 1.0 中已经提过了,这里讲的是动态的 metadata 的实现方式,主要是通过这个 generateMetadata 的方法自动生成的。 generateMetadata 也是一个保留词,具体使用方法如下:

export const generateMetadata = async ({ params }) => {const meal = await getMeal(params.mealSlug);return {title: meal.title,description: meal.summary,};
};

路由

这里再多提一些关于路由的内容,更多更完整的内容,还是可以到官方文档: **Project structure and organization** 中去去查找,并且自己测试试验,再根据项目需求判断是否需要

parallel routes

个人感觉,parallel routes 是一个更方便管理子组件的一种实现。官方文档中说了,parallel routes 的实现必须要依赖于 layout.js ,而且 parallel routes,也就是用 @folder 这种语法,会生成独立的 slot,但是不会生成独立的 URL

如下面这个案例:

@archive@latest 会作为两个独立的 slots,可以在 layout.js 中获取,但是它的路径还是在 localhost:3000/archive 下,单独访问 localhost:3000/archive/@archive 或是 localhost:3000/archive/@latest 会报错,因为 NextJS 内部并没有实现对应的路径

具体的排列方式如下:

import React from "react";const ArchiveLayout = ({ archive, latest }) => {return (<div><h1>News Archive</h1><section id="archive-filter">{archive}</section><section id="archive-latest">{latest}</section></div>);
};export default ArchiveLayout;

这种情况下, archivelatest 的内容会被并排渲染:

parallel routes + 动态路由

现在总体来说,需求还是比较明确的:

  • archive 显示按照年月分类的文档
  • latest 显示最近的几个文档

按照 NextJS 的结构,那么文档目录就应该是现在这个样子的:

不过这就造成了一个问题:

这是因为,parallel routes 中的路径存在不匹配的情况—— @archive 下有 [year],但是 @latest 下面没有,NextJS 没有办法完美匹配路径,因此就抛出了异常

这种情况下解决方式有两种:

  1. @latest 下也创立对应的 [year] 结构

    缺点就是语意不明确,而且会增加很多无意义的结构

    在当前的业务情况下,@latest 默认只会显示最近的几条数据,并不需要根据 年/月 进行搜索

  2. 使用 default.js

    default.js 是 parallel route 的 fallback 页面,具体实现如下:

    💡 这里的 default.js 中的内容和 page.js 完全一致,因此后期实现中将 page.js 删除了

最终渲染效果如下:

刚开始看到这个 @ 的用法还是不太理解,后面回顾了一下过去做的几个项目,发现这个 slots 还是可以比较好的解决过去项目中,我碰到的几个痛点:

  • 超大表单
    这个在填写付款方法、地址的时候经常碰上,不过我们那时候的业务场景更复杂一些,总体上来说大概会有 6-7 个 steps,每个 steps 的路径一致,但是表单不一样
  • 同一个路径中根据不同条件渲染不同内容

catch all route

其实 NextJS 还是提供了其他的不同实现方法,这个业务场景下,因为只有 年/月 的搜查,其实创建对应的文件夹结构也不是不行,而且对于 NotFound 的支持会更好一些。不过案例中选择用了 catch all route 这个也比较常见实现进行学习

组件部分的实现比较简单:

import NewsList from "@/app/_components/news-list";
import {getAvailableNewsMonths,getAvailableNewsYears,getNewsForYear,getNewsForYearAndMonth,
} from "@/app/_lib/news";
import Link from "next/link";
import React from "react";const FilteredNewsPage = ({ params }) => {const filter = params.filter;const selectedYear = filter?.[0];const selectedMonth = filter?.[1];let news;let links = getAvailableNewsYears();if (selectedYear && !selectedMonth) {news = getNewsForYear(selectedYear);links = getAvailableNewsMonths(selectedYear);} else if (selectedYear && selectedMonth) {news = getNewsForYearAndMonth(selectedYear, selectedMonth);links = [];}let newsContent = <p>No news found for the selected period.</p>;if (news?.length) {newsContent = <NewsList news={news} />;}return (<><header id="archive-header"><nav><ul>{links.map((link) => {const href = selectedYear? `/archive/${selectedYear}/${link}`: `/archive/${link}`;return (<li key={link}><Link href={href}>{link}</Link></li>);})}</ul></nav></header>{newsContent}</>);
};export default FilteredNewsPage;

这里需要注意的是 params 的返回值,从字符串变成了数组。这是 catch all 的特性,也就是拦截所有的 params

目录结构如下:

需要注意的是这种情况下, @archive 下的 page.js 就会导致冲突,因为 [[...filter]] 本身就拦截了所有的路径——前面也提到过了

最终效果如下:

http://www.dtcms.com/a/604715.html

相关文章:

  • 网站logo图标做水果网站需要些什么
  • 网站空间怎么建站长春网络推广seo
  • 做网站要先买域名吗WordPress页面批量生成
  • 专业做化妆品的网站南京网站建设推南京网站建设设计
  • 城市门户网站网络营销公司成功案例
  • 绍兴网站制作公司怎样做软件app软件
  • 国内好用的五款开源建站系统网站怎么开通微信支付
  • 网站制作价格 上海网站建站哪家公司好一点
  • 淄博高效网站建设加盟型网站建设
  • 网站建设问答企业网站推广制作教程
  • 梅州建站哪里好百度关键词检测工具
  • 一个网站如何优化国内网站排名
  • 服务器搭建网站能ping tapp界面设计模板素材免费
  • 做网站的数据库的设计vi设计流程
  • 国家工程建设标准化信息网站做二手交易网站如何盈利
  • 天津手网站开发百度站长平台闭站保护
  • 国外优秀网站谷歌浏览器下载安装2022
  • 全国知名网站建设wordpress 站点错误
  • 网站开发程序介绍佛山网页设计怎么做
  • 手机网站建设费用自建房平台设计
  • 最专业的营销网站建设做网站不给钱
  • 新乡公司网站建设wordpress5.2自动保存
  • 保亭交通工程建设局网站网站首页被降权怎么做
  • 网站建设 需要注意什么外链推广平台
  • 城关区建设局网站什么是搜索引擎推广
  • 广州城市职业学院门户网站jsp网站建设项目实战课后
  • 东莞建网站公司平台邢台123生活最新帖子
  • 平台网站建设 厦门wordpress 函数教程视频
  • 免费发短信的在线网站遵义住房和城乡建设厅网站
  • 一些你不知道的网站工程建筑公司