简单介绍

要从头开始使用 React 构建一个完整的 Web 应用程序,需要考虑许多重要的细节:

  • 必须使用打包程序(例如 webpack)打包代码,并使用 Babel 等编译器进行代码转换。
  • 你需要针对生产环境进行优化,例如代码拆分。
  • 你可能需要对一些页面进行预先渲染以提高页面性能和 SEO。你可能还希望使用服务器端渲染或客户端渲染。
  • 你可能必须编写一些服务器端代码才能将 React 应用程序连接到数据存储。
    一个 框架 就可以解决上述这些问题。但是,这样的框架必须具有正确的抽象级别,否则它将不是很有用。它还需要具有出色的“开发人员体验”,以确保您和您的团队在编写代码时拥有出色的体验。

Next.js 具有同类框架中最佳的“开发人员体验”和许多内置功能。列举其中一些如下:

  • 直观的、 基于页面 的路由系统(并支持 动态路由)
  • 预渲染。支持在页面级的 静态生成 (SSG) 和 服务器端渲染 (SSR)
  • 自动代码拆分,提升页面加载速度
  • 具有经过优化的预取功能的 客户端路由
  • 内置 CSS 和 Sass 的支持,并支持任何 CSS-in-JS
  • 开发环境支持 快速刷新
  • 利用 Serverless Functions 及 API 路由 构建 API 功能
  • 完全可扩展

上面引用与官网介绍

初始化项目

运行初始化项目命令:

yarn create next-app

添加 typescript、sass 支持

touch tsconfig.json

把 .js文件 改为 .tsx 或者 .ts

yarn add sass

项目初始目录如图:

  • paegs 所有页面都在这里编写,文件路由必须写在这个目录下面
  • public 存放静态资源
  • styles 样式

运行项目:

npm run dev


接下来我们开始改造项目,以便适应实际项目的应用开发。

思考

一般来说,我们从头开始搭建一个项目,需要考虑三个方面:

  • 布局
    布局不仅思考页面的整体布局如何,还得使用怎样的组件库,还是自己开发组件库等一下,这些东西要一开始就考虑,即使是自己写组件,也比后面才回头优化布局要好得多

  • 获取数据以及数据流
    获取数据主要分两点:同步异步,同步获取数据很好解决,直接使用函数调用即可,异步怎么搞?尤其是在使用redux处理数据流的时候,这时候需要加入类似 redux-saga 的中间件专门处理异步数据

  • 路由
    路由怎么配置以及需要怎样的权限管理

布局

Document、Layout

Document

Document 组件是有Next.js提供的,是对页面的结构一个抽象,方便与我们调整位置以及编写一些公共属性,Document的子组件如下:

  • Html,比如写 lang="zh"
  • Main
  • Head,编写一些 meta 标签的属性,比如:<meta name="theme-color"/> 主题颜色
  • NextScript
Layout

Layout 同样是由 Next.js提供,React 模型允许我们将一个页面解构为一系列组件。许多这些组件经常在页面之间重用。例如,可能在每个页面上都有相同的导航栏和页脚。

实现过程

创建 _document.tsx,在根目录创建 layout 目录,在 layout 目录下创建 index.tsx、sidebar.tsx,代码分别如下:

// _document.tsx
import Document, { DocumentContext, Head, Html, Main, NextScript } from 'next/document';class MyDocument extends Document {render() {return (<Html lang="zh"><Head><meta name="theme-color"/></Head><body><Main/><NextScript/></body></Html>);}
}MyDocument.getInitialProps = async (ctx: DocumentContext) => {const originalRenderPage = ctx.renderPage;ctx.renderPage = () =>originalRenderPage({// useful for wrapping the whole react treeenhanceApp: (App) => App,// useful for wrapping in a per-page basisenhanceComponent: (Component) => Component,});// Run the parent `getInitialProps`, it now includes the custom `renderPage`return await Document.getInitialProps(ctx);
};export default MyDocument;
// index.tsx
import Head from 'next/head'
import styles from './layout.module.scss'export default function Layout({ children }) {return (<><Head><title>My App</title><meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport"/></Head><main className={styles.main}>{children}</main></>)
}
import Link from 'next/link'
import styles from './sidebar.module.scss'export default function Sidebar() {return (<nav className={styles.nav}><Link href="/"><a>Home</a></Link><Link href="/about"><a>About</a></Link><Link href="/contact"><a>Contact</a></Link></nav>)
}

最终实现效果:

  • 源码链接

获取数据

  • getStaticProps(静态生成):在构建时获取数据。
  • getStaticPaths(静态生成):指定动态路由以根据数据预渲染页面。
  • getServerSideProps(服务器端渲染):获取每个请求的数据。

想要了解这三种方式,首先我们得对客户端渲染、服务端渲染有所了解
它支持三种渲染方式包括

  • 客户端渲染 BSR (Broswer Side Render)

  • 静态页面生成 SSG (Static Site Generation)

  • 服务端渲染 SSR (Server Side Render)
    旧瓶装新酒
    上面说的几种渲染方式,其实并非什么新东西,其实可以和这些技术对应起来

  • BSR – 用 JS、Vue、React 创建 HTML

  • SSG – 页面静态化,把 PHP 提前渲染成 HTML

  • SSR – PHP、Python、Ruby、Java 后台的基本功能

详情请点击

实现

在 pages 目录创建 about.tsx、contact.tsx、index.tsx,分别调用 getStaticProps 方法

about.tsx
import Layout from '../layout';
import Sidebar from '../layout/sidebar';
import { GetStaticProps } from "next";export default function About(props) {return (<section><h2>{props.title}</h2><p>{props.content} </p></section>);
}About.getLayout = function getLayout(page) {return (<Layout><Sidebar/>{page}</Layout>);
};export const getStaticProps: GetStaticProps = async () => {const res = await fetch('http://localhost:3000/json/about.json');const rsp = await res.json();return {props: {...rsp.data,},};
};
contact.tsx
import Layout from '../layout'
import Sidebar from '../layout/sidebar'
import { GetStaticProps } from "next";export default function Contact(props) {return (<section><h2>{props.title}</h2><p>{props.content} </p></section>)
}Contact.getLayout = function getLayout(page) {return (<Layout><Sidebar />{page}</Layout>)
}export const getStaticProps: GetStaticProps = async () => {const res = await fetch('http://localhost:3000/json/contact.json');const rsp = await res.json();return {props: {...rsp.data,},};
};
index.tsx
import Layout from '../layout';
import Sidebar from '../layout/sidebar';
import { GetStaticProps } from "next";export default function Index(props) {console.log(props);return (<section><h2>{props.title}</h2><p>{props.content} </p></section>);
}Index.getLayout = function getLayout(page) {return (<Layout><Sidebar/>{page}</Layout>);
};export const getStaticProps: GetStaticProps = async () => {const res = await fetch('http://localhost:3000/json/index.json');const rsp = await res.json();return {props: {...rsp.data,},};
};
最终效果图

Redux、React-Redux、Redux-soga、next-redux-wrapper

yarn add redux react-redux redux-soga next-redux-wrapper

创建 store 文件,分别创建 index.ts、rootReducers.ts、rootSagas.ts、user目录

index.ts

import { applyMiddleware, createStore, Middleware, StoreEnhancer, Store } from 'redux';
import { createWrapper, Context } from 'next-redux-wrapper';
import createSagaMiddleware, { Task } from 'redux-saga';import rootReducer from './rootReducers';
import rootSaga from './rootSagas';export interface SagaStore extends Store {sagaTask?: Task;
}const bindMiddleware = (middleware: Middleware[]): StoreEnhancer => {if (process.env.NODE_ENV !== 'production') {const { composeWithDevTools } = require('redux-devtools-extension');return composeWithDevTools(applyMiddleware(...middleware));}return applyMiddleware(...middleware);
};export const makeStore = (context: Context) => {const sagaMiddleware = createSagaMiddleware();const store = createStore(rootReducer, bindMiddleware([sagaMiddleware]));(store as SagaStore).sagaTask = sagaMiddleware.run(rootSaga);return store;
};export const wrapper = createWrapper(makeStore, { debug: true });

rootReducers.ts

import { combineReducers } from 'redux'
import user from './user/reducer'
import { HYDRATE } from 'next-redux-wrapper';const reducers = combineReducers({user,
});const rootReducers = (state: any, action: any) => {if (action.type === HYDRATE) {return { ...state, ...action.payload };}return reducers(state, action);
}export default rootReducers
rootSaga.ts
import { all } from "redux-saga/effects";
import user from "./user/soga";function* rootSaga() {yield all([...user]);
}export default rootSaga;
user目录
action.ts
export enum examplesTypes {EXAMPLES_01 = "EXAMPLES_01",EXAMPLES_02 = "EXAMPLES_02",EXAMPLES_ASYNC = "EXAMPLES_ASYNC",
}export function examples_01(result: any) {return {type: examplesTypes.EXAMPLES_01,payload: result,};
}export function examples_02(result: any) {return {type: examplesTypes.EXAMPLES_02,payload: result,};
}export function examplesAsync(result: any) {return {type: examplesTypes.EXAMPLES_ASYNC,payload: result,};
}
reducers.ts
import { examplesTypes } from './action'
import { HYDRATE } from 'next-redux-wrapper'
import { combineReducers } from "redux";
const initialState = {examples: "examples"
}function examplesData(state: any = initialState, action: any) {const { type, payload } = actionswitch (type) {case HYDRATE: {return { ...state, ...action.payload }}case examplesTypes.EXAMPLES_01:return {...state,...payload}case examplesTypes.EXAMPLES_02:return {...state,...payload}default:return state}
}const examples = combineReducers({examplesData,
});
export default examples;
soga.ts
import { all, call, fork, takeLatest } from 'redux-saga/effects'
import { examplesTypes } from './action'
import axios, { AxiosResponse } from 'axios';function* login() {try {} catch (err) {}
}interface IExamplesAsync {}function* examplesAsync() {try {const { status, data }: AxiosResponse<IExamplesAsync> = yield call(axios.get,'https://jsonplaceholder.typicode.com/users',);} catch (err) {}
}function* userSaga() {yield all([takeLatest(examplesTypes.EXAMPLES_ASYNC, examplesAsync),])
}let user = [fork(userSaga)];export default user;
最后调用测试一下
  useEffect(() => {dispatch(examplesAsync({ message: 'examplesAsync' }));}, []);

源码

源码链接

基于Next.js搭建基本可用于项目开发的过程相关推荐

  1. 基于VS Code搭建通用ARM微控制器开发平台

    基于VS Code搭建通用ARM微控制器开发平台 Data Author Version Note 2022.04.12 Dog Tao V1.0 Release as V1.0 - 使用基于STM3 ...

  2. java项目_好程序员Java分享从入门到服务端项目开发的过程

    好程序员Java分享从入门到服务端项目开发的过程,对于打算入门或者刚刚入门学习Java的人来说,刚开始接触这门学科,往往会觉得不知所措,也会觉得很迷茫.结合前人经验,就从入门到进阶对于Java的学习而 ...

  3. ASP.NET Core 实战:使用ASP.NET Core Web API 和 Vue.js 搭建前后端分离项目

    一.前言 这几年前端的发展速度就像坐上了火箭,各种的框架一个接一个的出现,需要学习的东西越来越多,分工也越来越细,作为一个 .NET Web 程序猿,多了解了解行业的发展,让自己扩展出新的技能树,对自 ...

  4. vue开发案例:基于Three.js搭建三维数字化场景

    0.场景涉及的关键技术点 GLTFLoader加载gltf模型,并解析模型动画: 基于worker-loader在vue中使用web worker: 基于web worker动态设置模型(鸟.牛)的移 ...

  5. 毕业设计-基于SSM框架大学教务管理平台项目开发实战教程(附源码)

    文章目录 1.项目简介 2.项目收获 3.项目技术栈 4.测试账号 5.项目部分截图 6.常见问题 毕业设计-基于SSM框架大学教务管理平台项目实战教程-附源码 课程源码下载地址:https://do ...

  6. SpringMVC 搭建maven的web项目、执行过程及原理分析

    该框架为学习刘先森课程所得 idea搭建maven的web项目 工程目录结构 创建一个maven工程并导入依赖 <dependencies><dependency><!- ...

  7. 基于android studio 安卓的汽车APP项目开发和设计

    一 项目介绍 汽车APP项目 包含了 APP客户端和后台管理系统,后台管理系统主要维护汽车的数据,比如汽车发布,汽车图集多图上传,汽车销售商,汽车类型,客户管理,系统管理等,APP客户端包含 用户注册 ...

  8. Androidstudio开发button按钮的操作以及项目开发大致过程

    随着应用Androidstudio的不断深入,对于一个Android项目的开发流程也是不断形成这自己的理解.笔者对于Android的学习时间比较晚,我没有使用eclipse对于Android进行开发学 ...

  9. 基于Voxel.js搭建网页方块世界游戏

    Voxel.js,是用于呈现在浏览器上的方块游戏的构建工具包

最新文章

  1. centos7中nfs文件系统的使用
  2. Java高级特性:clone()方法
  3. Ubuntu图形界面配置开机自启动
  4. cesium 3dtiles 加载本地数据_cesium结合geoserver实现地图空间查询(附源码下载)
  5. php判断ip地址小程序
  6. 第11章-img特征,vertical-align,cursor,opacity
  7. 黄金为什么贵,黄金都有什么用处?
  8. Python入门--__init__,__new__
  9. 锐文科技发布基于国产FPGA的智能网卡芯片
  10. 微信打不开MP4文件 (记录编码问题)
  11. Vue学习7-MinUI组件与项目托管到码云上
  12. Python学习之字典练习(重复数字统计)
  13. 一加8p和鸿蒙系统,网友热议话题:华为鸿蒙系统2.0曝新消息,一加8T口碑出炉...
  14. H3C交换机DHCP Snooping抑制局域网内非法dhcp
  15. 成都拓嘉启远:如何全面看待拼多多百亿补贴
  16. CodeVS3498 小木棍
  17. 2016谷歌重返中国,体验Google中国开发者网站
  18. 总感觉自己什么都不会,做什么都做不好怎么办?
  19. Python爬虫:史上最详细的Python爬虫库urllib讲解,绝对经典,值得收藏
  20. 数学中的伟大定理:海伦公式的推导过程

热门文章

  1. ThinkPad T14s 安装Ubuntu22踩坑记
  2. 欢迎光临 X.U.S.T 小组网站 !
  3. 江西省中小学生学籍管理-跨省办理平台数字证书(2)
  4. StringUtils的使用,数组转list,list转数组
  5. 2020年10月虹科Pico汽车示波器简报
  6. 数据之眼 | 数据探查服务的设计
  7. LKD (linux内核设计与实现)笔记
  8. 优化VR体验的7个建议
  9. PermissionError: [Errno 13] Permission denied: ‘E:\\data\\lianxi_out\\csv‘权限错误
  10. 易语言发信服务器没有反应,还不会使用易语言连接发信服务器发送邮件的朋友看过来...