nextjs
解决的问题
- 你需要针对生产环境进行优化,例如代码拆分。
- 对一些页面进行预先渲染以提高页面性能和
SEO。你可能还希望使用服务器端渲染或客户端渲染
优势: 适合React项目,相比其他服务端渲染的框架更为简单减少学习成本开箱即用
pages文件
pages 下的文件自动生成路由,pages/[id].js 生成动态路由
静态文件如图片可以放在根目录的 public 下面,对外可以直接访问 /
nextjs 提供自动刷新的功能,每次保存编译之后浏览器的页面会自动刷新,页面也会有每次轮询刷新的功能
预渲染
nextjs 预渲染每个页面,也就是会为每个页面是生成 HTML 文件,从而有更好的 SEO 效果
预渲染的方式
分成静态渲染和服务端渲染两种方式,区别在于静态渲染是在构建 HTML 的时候渲染,在每次页面请求的时候重新调用,服务端渲染是在每次发请求的时候渲染 html
当然也可以使用“两种方式混合渲染” , 更推荐静态渲染,有更好的效果
样式
项目中用到的样式有两种:
-
全局样式
- 使用之前要在
\_app.js里面引入全局就能使用了import '@/styles/globals.scss',一些插件的样式需要自己引入的也是用这种方式
- 使用之前要在
-
组件的样式
-
nextjs中支持css模块,文件命名为[name].module.css,使用的时候需要用引入文件点类名的方式className={styles.error} -
支持
Scss,不过要在next.config.js里面配置一些东西
sassOptions: { includePaths: [path.join(__dirname, 'src/styles')], },css in js, 项目中采用了 styled-components 插件,使用方法如下
import styled from "styled-components"; const PageWrap = styled.div` margin: 10px 100px; border: 1px solid #f0f0f0; padding: 20px; min-height: calc(100vh - 118px); `; const Page: NextPage = () => <PageWrap>...把之前的组件包裹住 </PageWrap>; -
因为我们项目在之前并没有用 CSS 模块,所以用 styled-components 迁移更方便容易,对于这两者的区别和选择可以看一下这篇文章《Css in Js 之 styled-components》
图片
nextjs 中的 image 组件对原生的做了扩展优化,无论加载多少图片都不会影响构建的速度,给图片加了懒加载的功能,图片进入视口才会加载
import Image from "next/image";
<Image src="/logo.png" alt="squid.io" width={500} height={500} />;
下面是 layout="fill" 也就是图片的宽高适应父元素的宽高,父元素必须有定位
<Image
src="/assets/index/bestHelp/diverse-database.svg"
alt="diverse-database"
layout="fill" //表示和有定位的父盒子一样大小
objectFit="contain"
/>
注意点:
- 图片资源最好放在
public相当于根目录就可以直接引用图片文件路径了 - 图片必须要给宽高或
layout="fill",以及alt - 图片就会有默认样式
absolute,如果图片上面还有absolute的文字就会被遮盖住,把文字的层级加一下就行了z-index
next/image 导出标签常用属性
必选
src width height alt
可选
layout视口尺寸变化是图片布局的行为,参数intrinsic默认 缩小不放大,fixed固定大小,responsive缩小放大,fill拉升与父元素一样大quality图片优化后质量 默认是75prioritytrue图片优先级最高,默认为falseplaceholder占位,blur模糊empty空白style代替classNamedecoding代替async更多属性 >
Script
引入一些脚本文件可以使用下面集中方法
import Head from "next/head";
<Head>
<script async src="https://www.google-analytics.com/analytics.js" />
</Head>;
import Script from "next/script";
<Script src="https://www.google-analytics.com/analytics.js" />;
当想要在处理一些逻辑可以使用,比如广告脚本
<Script strategy="lazyOnload">
{`处理逻辑`}
</Script>
// or
<Script
dangerouslySetInnerHTML={{
__html: `处理逻辑`
}}
/>
<Script
id="stripe-js"
src="https://js.stripe.com/v3/"
onLoad={() => {
处理逻辑;
}}
/>
路由
nextjs 中的路由是放在 pages/文件夹里面就可以生成路由如pages/blog.tsx 的路由就是 /blog
动态路由可以在 pages 文件夹下面建立如 pages/[id].tsx 的文件,就可以路由到 /pages/112 等路由下面
路由跳转可以通过 next/router 里的 useRouter
import { useRouter } from "next/router";
function Blog() {
const router = useRouter();
router.push("/login");
}
常用属性:
pathname路径query路径中的变量 更多 >
静态路由跳转可以使用 next/link
import Link from "next/link";
<Link href="/blog?id=1" replace>
<a>Link</a>
</Link>;
注意
link标签下面要是纯文字或是 a 标签,否则会有警告"Multiple children were passed to"在link标签里的子元素必须有一个父元素
配置国际化
next.config.js文件里的配置
// next.config.js
module.exports = {
i18n: {
locals: ["en", "zh"], //支持语言
defaultLocale: "en", // 默认的语言
localeDetection: false, //自动区域检测,在访问路由的时候通过请求Accept-Language来自动检测用户的语言,并在路径中显示
},
};
- 在
\_app里引入
import { appWithTranslation } from "next/i18n";
const App = ({ Component, pageProps }: AppProps): JSX.Element => (
<Component {...pageProps} />
);
export default appWithTranslation(App);
- 导入国际化配置文件
public/locales/en/common.json
public/locales/zh/common.json
- 在页面中请求国际化配置文件
import {serverSideTranslations} from next-i18n/serverSideTranslations
export const getStaticProps: GetStaticProps = async ({locale}) => ({
props: {
...(await serverSideTranslations(locale ?? 'zh',['common']))
}
})
- 在组件中使用
import { useTranslation } from 'next-i18next'
const {t} = useTranslation()
<div>{t('hello')}</div>
获取数据
getStaticProps 获取本地的数据
静态生成,在 build的时候获取数据,它是一个异步的方法
这是获取 public/locale/zh/common.json 翻译文件
const getStaticProps: GetStaticProps = aycnc ({locale}) => ({
props: {
...(await serverSideTranslation(locale ?? 'zh',['common']))
}
})
配置根据环境自动切换的 url
- 在
public/config/base-url.json下配置默认访问的路径
{
"config": "http://localhost:3000"
}
- 用
fetcher请求到上面的json数据并返回它
export type BaseUrlConfig = {
console: string
}
const getBaseUrl = async (): Promise<BaseUrlConfig> => {
const baseUrl: BaseUrlConfig = { console: '' }
try {
const res = await fetch('/config/base-url.json')
const config = (await res.json()) as BaseUrlConfig
return config
} catch (error) {
console.error(error)
}
return baseUrl
}
export default getBaseUrl
- 封装一个请求这个地址的
hook
import useSWR from "swr";
import getBaseUrl, { BaseUrlConfig } from "@/utils/getBaseUrl";
const useConfigUrl = (): BaseUrlConfig | undefined => {
const { data } = useSWR("base-url", getBaseUrl);
return data;
};
export default useConfigUrl;
- 在页面中使用
import useConfigUrl from "@/hooks/useConfigUrl";
const config = useConfigUrl();
next.config.js 配置
请求代理配置
遇到问题
-
样式 写成
xxx.module.css报错Selector "&::after" is not pure (pure selectors must contain at least one local class or id)原因:在
import styles from './index.module.scss'引入样式文件之后要用文件名点类名才能使用className={styles.alertMes} -
window is not define原因:在window这个全局对象是运行在浏览器中的,在服务端渲染中是没有的,所以会报错解决方法
- 对于组件 可以使用动态导入(next/dynamic)的方式
import dynamic from "next/dynamic"; const WebHeader = dynamic(async () => import("@/components/WebHeader")); return <WebHeader />;- 在使用
window的地方可以添加条件判断
if (typeof window !== "undefined") { return window.localStorage; } -
nextjs里面写的函数方法都要导出