常春玉露 發表於 2023-1-10 18:41:00

Next.js入门

<h2 id="next-特点">Next 特点</h2>
<p>next 适合用于公司官网、文章类、电商类等对于 SEO 需求高的网站。<br>
中后台管理系统无需 SEO 所以也不一定需要使用 Next</p>
<h2 id="创建-nextjs-应用">创建 Next.js 应用</h2>
<pre><code class="language-sh">npx create-next-app nextjs-blog --use-npm --example "https://github.com/vercel/next-learn/tree/master/basics/learn-starter"

cd nextjs-blog

npm run dev
</code></pre>
<h2 id="路由">路由</h2>
<p>Next 中路由就是对应的文件路径</p>
<p>例如,在开发中:</p>
<p>pages/index.js与/路线相关联。<br>
pages/posts/first-post.js与/posts/first-post路线相关联。</p>
<h3 id="link">Link</h3>
<p><code>&lt;Link&gt;</code> 用于在页面中导航</p>
<pre><code class="language-jsx">import Link from 'next/link';
&lt;h1 className="title"&gt;
Read &lt;Link href="/posts/first-post"&gt;this page!&lt;/Link&gt;
&lt;/h1&gt;
</code></pre>
<blockquote>
<p>在 Next.js 的生产版本中,每当Link组件出现在浏览器的视口中时,Next.js 都会在后台自动预取链接页面的代码。当您单击链接时,目标页面的代码已经在后台加载,页面转换几乎是即时的!</p>
</blockquote>
<h2 id="资源-css-等">资源 css 等</h2>
<h3 id="静态文件服务">静态文件服务</h3>
<p>Next 可以以 <code>public</code> 为基础,在根目录中的一个文件夹下提供静态文件服务,从基本 <code>baseURL</code>/ 开始引用 <code>public</code> 其中的文件<br>
例如:public/me.png 对应 <code>http://localhost:3000/me.png</code><br>
这点跟 <code>vue-cli</code> 和 <code>rca</code> 类似</p>
<h3 id="css">css</h3>
<p>Next 支持 CSS Modules</p>
<blockquote>
<p>重要提示:要使用CSS 模块,CSS 文件名必须以.module.css</p>
</blockquote>
<h4 id="使用-sass">使用 Sass</h4>
<pre><code class="language-sh">npm install -D sass
</code></pre>
<h3 id="图片">图片</h3>
<pre><code class="language-jsx">import Image from 'next/image';

const YourComponent = () =&gt; (
&lt;Image
    src="/images/profile.jpg" // Route of the image file
    height={144} // Desired size with correct aspect ratio
    width={144} // Desired size with correct aspect ratio
    alt="Your Name"
/&gt;
);
</code></pre>
<h3 id="head">head</h3>
<pre><code class="language-jsx">import Head from 'next/head';
// 直接会渲染到 head 标签中
&lt;Head&gt;
&lt;title&gt;Create Next App&lt;/title&gt;
&lt;link rel="icon" href="/favicon.ico" /&gt;
&lt;/Head&gt;
</code></pre>
<h2 id="全局样式">全局样式</h2>
<p>要加载全局 CSS文件,请创建一个名为的文件pages/_app.js,其内容如下</p>
<pre><code class="language-jsx">// `pages/_app.js`
import '../styles/global.css';
export default function App({ Component, pageProps }) {
return &lt;Component {...pageProps} /&gt;;
}
</code></pre>
<p>该App组件是所有不同页面通用的顶级组件。例如,您可以使用此App组件在页面之间导航时保​​持状态</p>
<h3 id="添加-layout-组件">添加 layout 组件</h3>
<p>layout 组件</p>
<p>。</p>
<h2 id="预渲染">预渲染</h2>
<h3 id="两种形式的预渲染">两种形式的预渲染</h3>
<p>Next.js 有两种预渲染形式:静态生成和服务器端渲染。不同之处在于它何时为页面生成 HTML</p>
<ul>
<li>静态生成是在构建时生成 HTML 的预渲染方法。然后在每个请求上重用预呈现的 HTML</li>
<li>服务器端渲染是在每个请求上生成 HTML 的预渲染方法。</li>
</ul>
<h3 id="静态生成">静态生成</h3>
<h4 id="getstaticprops">getStaticProps</h4>
<p>getStaticProps 仅在服务器端运行</p>
<p>开发与生产</p>
<ul>
<li>在开发(npm run dev或yarn dev)中,getStaticProps在每个请求上运行。</li>
<li>在生产中,getStaticProps 在构建时运行。但是,可以使用返回的fallback键来增强此行为 getStaticPaths</li>
</ul>
<p>我们建议尽可能使用静态生成(有数据和无数据),因为您的页面可以构建一次并由 CDN 提供服务,这比让服务器在每次请求时呈现页面要快得多。</p>
<p>您可以将静态生成用于多种类型的页面,包括:</p>
<ul>
<li>营销页面</li>
<li>博客文章</li>
<li>电子商务产品列表</li>
<li>帮助和文档</li>
</ul>
<pre><code class="language-jsx">// 服务端
export async function getStaticProps() {
const allPostsData = getSortedPostsData();
return {
    props: {
      allPostsData,
    },
};
}
// 客户端
export default function Home({ allPostsData }) {
const = useState(false);
return (
    &lt;Layout home&gt;
      &lt;section className={`${utilStyles.headingMd} ${utilStyles.padding1px}`}&gt;
      &lt;h2 className={utilStyles.headingLg}&gt;Blog&lt;/h2&gt;
      &lt;ul className={utilStyles.list}&gt;
          {allPostsData.map(({ id, date, title }) =&gt; (
            &lt;li className={utilStyles.listItem} key={id}&gt;
            {title}
            &lt;br /&gt;
            {id}
            &lt;br /&gt;
            {date}
            &lt;/li&gt;
          ))}
      &lt;/ul&gt;
      &lt;/section&gt;
    &lt;/Layout&gt;
);
}

</code></pre>
<p><strong>注意事项</strong></p>
<ul>
<li>因为它仅在构建时运行,所以您将无法使用仅在请求期间可用的数据,例如查询参数或 HTTP 标头。</li>
<li>仅允许在页面中, getStaticProps只能从页面导出。您不能从非页面文件中导出它。这种限制的原因之一是 React 需要在呈现页面之前拥有所有必需的数据</li>
<li>因为它仅在构建时运行 所以无法获取实时数据(仅适用于类似 静态博客 这种案例)</li>
</ul>
<h3 id="服务器端渲染">服务器端渲染</h3>
<p>如果您需要在请求时而不是在构建时获取数据,您可以尝试服务器端渲染:</p>
<p>getServerSideProps</p>
<pre><code class="language-js">export async function getServerSideProps(context) {
return {
    props: {
      // props for your component
    },
};
}

</code></pre>
<p>与 SEO 无关的私人、用户特定页面使用服务器端渲染</p>
<h3 id="预渲染-总结">预渲染 总结</h3>
<p>优先使用<code>静态生成</code> 实在不能使用<code>静态生成</code>的地方再使用<code>服务器端渲染</code>或<code>客户端渲染</code></p>
<h4 id="静态生成原理">静态生成原理</h4>
<p>每个文件对应一个页面,每个页面构建时都会先执行一下 <code>getStaticProps</code>,将 <code>props</code>传递给页面组件,然后根据页面组件生成对应的<code>html</code>, 浏览器直接请求对应的<code>html</code>会包含样式,所以即使禁用<code>javascript</code>还是可以正常浏览</p>
<h2 id="动态路由">动态路由</h2>
<p>动态路由同静态生成类似,需要有静态数据用于生成对应的路由和页面</p>
<p>我们希望每个帖子都有 <code>path/posts/id</code><br>
首先,我们将在pages/posts创建一个名为<code>.js</code>的页面。 注意是<code></code>需要带 <code>[]</code></p>
<h3 id="getstaticpaths">getStaticPaths</h3>
<p><code>.js</code> 文件导出 <code>getStaticPaths</code> 函数</p>
<p>.js</p>
<pre><code class="language-jsx">
export default function Post({ postData }) {
return (
    &lt;Layout&gt;
      {/* Add this &lt;Head&gt; tag */}
      &lt;Head&gt;
      &lt;title&gt;{postData.title}&lt;/title&gt;
      &lt;/Head&gt;
      &lt;article&gt;
      &lt;h1 className={utilStyles.headingXl}&gt;{postData.title}&lt;/h1&gt;
          {postData.date}
      &lt;div dangerouslySetInnerHTML={{ __html: postData.contentHtml }} /&gt;
      &lt;/article&gt;
    &lt;/Layout&gt;
);
}
/*
paths 是所有 id 的集合 (所有 /posts/* 的集合, ps:告诉 next 构建时需要生成哪些页面和路由)
paths [
{ params: { id: 'pre-rendering' } },
{ params: { id: 'ssg-ssr' } },
{ params: { id: 'vue原理' } }
]
params 中的参数和文件名 .js 需要对应.js =&gt; params.id
*/
export async function getStaticPaths() {
// Return a list of possible value for id
// Returns an array that looks like this:
// { params: { id: 'pre-rendering' } },
// { params: { id: 'ssg-ssr' } },
let paths = getAllPostIds();
return {
    paths,
    fallback: true, // 如果fallback是false,则任何无法匹配的路径getStaticPaths都将导致404 页面。 true 则会报错
};
}

// 这里返回的 props 将传递给Post 组件
// 构建时 next 直接根据 postData 生成对应页面
export async function getStaticProps({ params }) {
// Fetch necessary data for the blog post using params.id
// postData : { contentHtml datetitle}
const postData = await getPostData(params.id);
return {
    props: {
      postData,
    },
};
}


</code></pre>
<h3 id="getstaticpaths-中的--fallback-参数">getStaticPaths 中的fallback 参数</h3>
<p>如果fallback是</p>
<ul>
<li>false,则任何无法匹配的路径getStaticPaths都将导致404 页面。</li>
<li>true 则会报错</li>
<li>如果fallback是blocking,那么新路径将在服务器端呈现getStaticProps,并缓存以供将来的请求使用,因此每个路径仅发生一次。</li>
</ul>
<h3 id="多重路径动态路由">多重路径动态路由</h3>
<p>...通过在括号内添加三个点 ( ) 可以扩展动态路由以捕获所有路径例如:</p>
<ul>
<li>pages/posts/[...id].js匹配/posts/a, 但也/posts/a/b,/posts/a/b/c等等。<br>
如果你这样做, in getStaticPaths,你必须返回一个数组作为id键的值,如下所示:</li>
</ul>
<pre><code class="language-js">return [
{
    params: {
      // Statically Generates /posts/a/b/c
      id: ['a', 'b', 'c'],
    },
},
//...
];
</code></pre>
<p>并且params.id将是一个数组getStaticProps:</p>
<pre><code class="language-jsx">export async function getStaticProps({ params }) {
// params.id will be like ['a', 'b', 'c']
}

</code></pre>
<h3 id="router">router</h3>
<p>如果你想访问 Next.js 路由器,你可以通过useRouter从next/router.</p>
<h3 id="404页">404页</h3>
<p>要创建自定义 404 页面,请创建pages/404.js. 该文件是在构建时静态生成的</p>
<h2 id="api-接口">API 接口</h2>
<p>使用 Next 创建 api 接口,跟创建页面类似,可以使用文件路由的形式 <code>pages/api</code> 下创建对应的接口文件</p>
<p>在<code>pages/api</code> 下 创建 <code>hello.js</code></p>
<pre><code class="language-js">export default function handler(req, res) {
res.status(200).json({ text: 'Hello' });
}

</code></pre>
<p>尝试在http://localhost:3000/api/hello访问它。你应该看到{"text":"Hello"}。</p>
<h3 id="文章接口实现利用-next-api">文章接口实现(利用 next API)</h3>
<h4 id="创建文件">创建文件</h4>
<ul>
<li><code>pages/api/post/index.js</code>-&gt; http://localhost:3000/api/post // 获取所有文章数据</li>
<li><code>pages/api/post/.js</code>-&gt; http://localhost:3000/api/post/postId // 获取单个文章数据</li>
<li><code>pages/api/post/ids.js</code>-&gt; http://localhost:3000/api/post/ids // 获取所有文章的id</li>
</ul>
<p><code>pages/api/post/index.js</code></p>
<pre><code class="language-js">// 查询全部
import { getSortedPostsData } from "../../../lib/posts";

export default function handler(req, res) {
let PostsDatas = getSortedPostsData();
res.status(200).json(PostsDatas);
}
</code></pre>
<p><code>pages/api/post/.js</code></p>
<pre><code class="language-js">import { getPostData } from "../../../lib/posts";

// 查询单个
export default async function handler(req, res) {
const { postId } = req.query;
try {
    let data = await getPostData(postId);
    res.status(200).json(data);
} catch (error) {
    res.status(500).json({ error: "failed to load data" });
}
}
</code></pre>
<p><code>pages/api/post/ids.js</code></p>
<pre><code class="language-js">// id list
import { getAllPostIds } from "../../../lib/posts";

export default function handler(req, res) {
let data = getAllPostIds();
res.status(200).json(data);
}

</code></pre>
<h3 id="官方文档">官方文档</h3>
<p>动态 API 路由<br>
请求助手<br>
响应助手</p>
<h2 id="部署到-vercel">部署到 Vercel</h2>
<p>官方教程</p>
<h3 id="vercel">Vercel</h3>
<p>Next.js 和 Vercel<br>
Vercel由 Next.js 的创建者制作,并为 Next.js 提供一流的支持。当您将 Next.js 应用程序部署到Vercel时,默认情况下会发生以下情况:</p>
<p>使用静态生成和资产(JS、CSS、图像、字体等)的页面将自动从速度极快的Vercel 边缘网络提供服务。<br>
使用Server-Side Rendering和API 路由的页面将自动成为孤立的Serverless Functions。这允许页面呈现和 API 请求无限扩展</p>
<h3 id="流程">流程</h3>
<ul>
<li>源代码上传 github</li>
<li>注册 Vercel</li>
<li>[导入github项目](https 😕/vercel.com/import/git)(导入时会提示安装Vercel)</li>
</ul>
<p>添加后vercel根据分支自动部署(相当于预配置好的git action)</p>
<h3 id="预览">预览</h3>
<ul>
<li>创建预览分支</li>
<li>修改并上传预览分支</li>
<li>回到 github 仓库 会看到提示添加 Pull requests 根据提示添加 Pull requests</li>
<li>进到新创建的 Pull requests 中可以查看预览分支 部署好的页面<br>
<img src="https://s2.loli.net/2023/01/15/w4gZXHt8c2isbzD.png"></li>
<li>预览分支没问题就可以合并到主分支了</li>
</ul>
<h3 id="自定义域名">自定义域名</h3>
<p>自定义域名</p>
<ul>
<li>进入项目setting</li>
<li>选择域菜单项</li>
<li>添加域名随便写个域名会提示正确的域名填写方式</li>
<li>添加域名 (同时添加域名解析CNAME cname.vercel-dns.com)</li>
<li>添加预览域名 (同时添加域名解析 CNAME cname.vercel-dns.com)</li>
</ul>
<h2 id="环境变量">环境变量</h2>
<h3 id="环境变量加载顺序">环境变量加载顺序</h3>
<p>环境变量按顺序在以下位置查找,一旦找到变量就停止。</p>
<ul>
<li>process.env</li>
<li>.env.$(NODE_ENV).local</li>
<li>.env.local(未检查何时 NODE_ENV 是 test。)</li>
<li>.env.$(NODE_ENV)</li>
<li>.env<br>
例如,如果NODE_ENVis并且您在 and development中都定义了一个变量,则将使用in 中的值 <code>.env.development.local</code> <code>.env</code> .env.development.local</li>
</ul>
<p>注意:NODE_ENV允许的值为 production,development 和 test。</p><br><br>
来源:https://www.cnblogs.com/bitbw/p/17041107.html
頁: [1]
查看完整版本: Next.js入门