Next.js项目初始化(附gitHub地址)

Next.js项目初始化

1.脚手架搭建

npx create-next-app@latest

生成目录:

我生成的package.json:

javascript 复制代码
{
  "name": "nest-initial-demo",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@types/node": "20.6.0",
    "@types/react": "18.2.21",
    "@types/react-dom": "18.2.7",
    "eslint": "8.49.0",
    "eslint-config-next": "13.4.19",
    "next": "13.4.19",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "typescript": "5.2.2"
  }
}

2.样式依赖安装

  • npm i normalize.css --save
  • npm i sass --save
  • npm i classnames --save

引入全局

javascript 复制代码
import "normalize.css";
import "@/styles/globals.scss";
import type { AppProps } from "next/app";

export default function App({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />;
}

tsconfig.json@引入配置

3.head配置:

javascript 复制代码
// 这个四个属性是必须的
import { Html, Head, Main, NextScript } from "next/document";
export default function Document() {
  return (
    <Html lang="en">
      <Head>
        <meta name="description" content="react next demo" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <body className="hy-body">
        <Main />
        <NextScript />
      </body>
    </Html>
  );
}

3.reduxjs/toolkit集成

npm i next-redux-wrapper --save

  • 可以避免在访问服务器端渲染页面时store的重置
  • 该库可以将服务器端redux存的数据,同步一份到客户端上
  • 该库提供了HYDRATE调度操作
    • ➢ 当用户访问动态路由或后端渲染的页面时,会执行Hydration来保持两端数据状态一致
    • ➢ 比如:每次当用户打开使用了getStaticProps或getServerSideProps函数生成的页面时,HYDRATE将执行调度操作。

npm i @reduxjs/toolkit react-redux --save

numberDemo

typescript 复制代码
import { createSlice } from "@reduxjs/toolkit";
import { HYDRATE } from "next-redux-wrapper";

const numberSlice = createSlice({
  name: "numberDemo",
  initialState: {
    counter: 100,
  },
  reducers: {
    // 默认参数就有类型提示了
    increment(state, action) {
      state.counter = action.payload + state.counter;
    },
  },
  extraReducers: (builder) => {
    builder.addCase(HYDRATE, (state, action: any) => {
      return {
        ...state, // 当前模块的state
        ...action.payload.home, // payload:rootSate
      };
    });
  },
});
export const { increment } = numberSlice.actions;
export default numberSlice.reducer;

extraReducer:添加更多额外reducer处理other action

app集成
tsx 复制代码
import "normalize.css";
import "@/styles/globals.scss";
import type { AppProps } from "next/app";
import Layout from "@/components/C-user/layout";
import warpper from "../store";
import { Provider } from "react-redux";

export default function App({ Component, ...rest }: AppProps) {
  const { store, props } = warpper.useWrappedStore(rest);
  return (
    <div>
      <Provider store={store}>
        <Layout>
          <Component {...props.pageProps} />
        </Layout>
      </Provider>
    </div>
  );
}
使用
tsx 复制代码
import { useDispatch, useSelector } from "react-redux";
import { IAppDispatch, IAppState } from "../store";
import { increment } from "@/store/C-demo/numberDemo";

export default function Home() {
  const { numberDemo } = useSelector((rootState: IAppState) => {
    return {
      numberDemo: rootState.numberDemo.counter,
    };
  });
  const dispatch: IAppDispatch = useDispatch();
  function addNumber() {
    dispatch(increment(2));
  }
  return (
    <div style={{ minHeight: "400px", background: "#DADAE5" }}>
      <button onClick={addNumber}>add2</button>
      number:{numberDemo}
    </div>
  );
}

requestDemo

typescript 复制代码
import { getHomeInfoData } from "@/service/user/index";
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import { HYDRATE } from "next-redux-wrapper";
export interface IHomeInfo {
  banners?: any[];
  categorys?: any[];
  recommends?: any[];
  digitalData?: any;
}
interface IInitialState {
  requestDemoInfo: IHomeInfo;
}
const requestSlice = createSlice({
  name: "requestDemo",
  initialState: {
    requestDemoInfo: {},
  } as IInitialState,
  reducers: {
    // 默认参数就有类型提示了
    changeNavbarAction(state, action) {
      state.requestDemoInfo = action.payload;
    },
  },
  extraReducers: (builder) => {
    builder.addCase(HYDRATE, (state, action: any) => {
      return {
        ...state,
        ...action.payload.requestDemo, // hydration home模块数据
      };
    });
  },
});
// 异步的action
export const fetchHomeInfoAction = createAsyncThunk(
  "fetchHomeInfoAction",
  async (payload: number, { dispatch }) => {
    // console.log("payload=>", payload);
    const res = await getHomeInfoData();
    dispatch(requestSlice.actions.changeNavbarAction(res.data));
  }
);

export const { changeNavbarAction } = requestSlice.actions;
export default requestSlice.reducer;

index使用

typescript 复制代码
import { useDispatch, useSelector } from "react-redux";
import { IAppDispatch, IAppState, wrapper } from "@/store/index";
import { increment } from "@/store/C-demo/numberDemo";
import { GetServerSideProps } from "next";
import { getHomeInfoData } from "@/service/user";
import { useCallback, useEffect, useState } from "react";
import { fetchHomeInfoAction } from "@/store/C-demo/requestDemo";
interface listRoot {
  id: number;
  productId: number;
  picId: number;
  backendPicId: number;
  addTime: number;
  position: number;
  type: number;
  url: string;
  bannerExtJson: any;
  isSetTime: number;
  beginTime: number;
  endTime: any;
  picStr: string;
  backendPicStr: string;
}

export default function Home() {
  const { numberDemo } = useSelector((rootState: IAppState) => {
    return {
      numberDemo: rootState.numberDemo.counter,
    };
  });
  const { requestDemo } = useSelector((rootState: IAppState) => {
    return {
      requestDemo: rootState.requestDemo.requestDemoInfo,
    };
  });
  const dispatch: IAppDispatch = useDispatch();
  function addNumber() {
    dispatch(increment(2));
  }
  const [bannersList, setBannersList] = useState<listRoot[]>([]);
  const getUserCb = useCallback(() => getHomeInfoData(), [numberDemo]);
  useEffect(() => {
    getUserCb()
      .then((res) => {
        console.log(res);
        if (res.data.banners) setBannersList(res.data.banners);
      })
      .catch((err) => {
        console.log(err);
      });
  }, [getUserCb]);
  return (
    <div style={{ minHeight: "400px", background: "#DADAE5" }}>
      <button onClick={addNumber}>add2</button>
      number:{numberDemo}
      <div>
        直接的List:
        <ul>
          {bannersList.map((item) => {
            return <li key={item.id}>{item.picStr}</li>;
          })}
        </ul>
        redux的List:
        {requestDemo?.banners && (
          <ul>
            {requestDemo?.banners.map((item) => {
              return <li key={item.id}>{item.picStr}</li>;
            })}
          </ul>
        )}
      </div>
    </div>
  );
}

export const getServerSideProps: GetServerSideProps =
  wrapper.getServerSideProps(function (store) {
    return async (context) => {
      await store.dispatch(fetchHomeInfoAction(1));
      return {
        props: {},
      };
    };
  });

集成网络请求request封装

npm install axios

src建立service文件:

4.集成ant-design

npm install antd --save

npm install @types/antd --save-dev

_app全局导入:

import "antd/dist/reset.css";

页面调用:

import { Button } from "antd";

Github地址

https://github.com/wzz778/nest-initial-demo

相关推荐
祥Sir的SRE笔记4 小时前
CPU 100% 不一定是故障:压测打满、业务饱和、突变打满的判断与排查
linux·面试·性能优化·dba·sre·故障定位·性能排查
seowmt4 小时前
GEO效果该什么时候看数据:从立项到复盘的时间线复盘
算法·ip·seo·geo·faq
Sayai4 小时前
Elasticsearch 日志写入链路调优实战:ingest pipeline 补时间戳、时区偏移修复与按值类型路由(附 translog 实测)
大数据·运维·elasticsearch·搜索引擎·性能优化
楚识科技5 小时前
内网环境 OCR 服务搭建:私有化部署的技术实现与性能优化
性能优化·ocr
利威尔xu7 小时前
万字详解 | Go 进阶(二)GC 三色标记:STW 从 10ms 压到 40μs,1 次 Full GC 让线上 P99 抖了 3 秒
开发语言·后端·性能优化·golang·高并发
SEO_juper7 小时前
Node.js 全站死链检测工具:从 sitemap 出发一次找全 404
开发语言·人工智能·python·node.js·seo·外贸独立站
wuyk5558 小时前
模块解耦实战:用 C 语言实现面向对象编程的三个层次
stm32·单片机·嵌入式硬件·性能优化·架构
Gauss松鼠会8 小时前
GaussDB 内存相关参数及故障诊断
运维·数据库·sql·oracle·性能优化·架构·gaussdb
九蝶科技9 小时前
金蝶云星空 BOS 插件性能优化:把 N+1 查询、事件重算和长事务干掉
性能优化
程序员清风9 小时前
大文件处理与性能优化:分块读取、类型优化与向量化
性能优化