使用next.js创建react+ts项目
一. 运行创建命令
yarn create next-app “文件名” --typescript
安装完成后:
去到创建的文件里,运行yarn dev启动开发服务器。
然后打开浏览器,输入地址:http://localhost:3000/,就能看到你的项目。
具体可以参考next.js官网,有详细的说明,npm或者pnpm都有。
二. 配置
安装ESLint和Prettier
1.ESLint
从11.0.0版本开始,Next.js 提供了开箱即用的集成ESLint体验。Next.js 自动安装eslint并eslint-config-next作为开发依赖项在您的应用程序中,并在项目的根目录中创建一个.eslintrc.json包含您选择的配置的文件。
1)初始化
npx eslint --init
根据提示安装相关插件以及选择相关配置。
它会自动生成eslint的配置文件。
2)配置开发工具(vscode)能ctrl+s自动修复格式错误。
1>. 在vscode中安装eslint插件。
2>. 在vscode设置,让eslint插件显示在状态栏"eslint.alwaysShowStatus": true
3>. 管理-–>设置—>工作区设置 --> 打开json设置—>自动创建.vscode/settings.json文件,添加如下内容:(不要配置 用户级别!不要配置 用户级别!不要配置 用户级别!)
{
"eslint.run": "onType", // 运行linter 的时间,onSave(保存后)或onType(输入时),默认为onType
"eslint.options": {
"extensions": [".js", ".vue", ".jsx", ".tsx"]//指定vscode的eslint所处理的文件的后缀
},
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true // 保存时按eslint自动修复
}
}
2.Prettier
yarn add --dev prettier
3.解决 Prettier 和 ESLint 的冲突
1)安装两个依赖包
eslint-plugin-prettier //将 Prettier 的规则设置到 ESLint 的规则中。
eslint-config-prettier //关闭 ESLint 中与 Prettier 中会发生冲突的规则。
yarn add --dev eslint-plugin-prettier eslint-config-prettier
2)在.eslint的配置文件中添加 prettier 插件
module.exports = {
...
extends: [
'plugin:prettier/recommended' // 添加 prettier 插件
],
...
}
安装tailwindcss
1)下载依赖包
yarn add --dev tailwindcss@latest postcss@latest autoprefixer@latest
2)生成tailwindcss配置文件:
npx tailwindcss init -p
此时项目里会多出两个文件:tailwind.config.js和postcss.config.js
3)修改tailwind.config.js文件里的content为:
content: [
"./pages/**/*.{js,ts,jsx,tsx}",
"./components/**/*.{js,ts,jsx,tsx}",
"./styles/**/*.css",
],
意思是说这些文件都可以使用tailwind。
4)将style/globals.css文件中的内容改成
@tailwind base;
@tailwind components;
@tailwind utilities;
添加loading-bar,增加用户体验。
1.首先了解一哈用到的东西
我们此时就要用到next/router的router.event,翻译成中文就是路由器事件了
2. 添加loading用到的依赖@tanem/react-nprogress
yarn add @tanem/react-nprogress
依赖的地址中有很多Live Examples
这个就是关于nextJs的案例。
创建一个components/Loading.tsx
import { useNProgress } from '@tanem/react-nprogress';
const GlobalLoading = ({ isRouteChanging, }) => {
const { animationDuration, isFinished, progress } = useNProgress({
isAnimating: isRouteChanging,
})
return (
<>
<style jsx>{`
.container {
opacity: ${isFinished ? 0 : 1};
pointerevents: none;
transition: opacity ${animationDuration}ms linear;
}
.bar {
background: #29d;
height: 2px;
left: 0;
margin-left: ${(-1 + progress) * 100}%;
position: fixed;
top: 0;
transition: margin-left ${animationDuration}ms linear;
width: 100%;
z-index: 1031;
}
.spinner {
box-shadow: 0 0 10px #29d, 0 0 5px #29d;
display: block;
height: 100%;
opacity: 1;
position: absolute;
right: 0;
transform: rotate(3deg) translate(0px, -4px);
width: 100px;
}
`}</style>
<div className="container">
<div className="bar">
<div className="spinner" />
</div>
</div>
</>
)
};
export default GlobalLoading;
_app.jsx中使用
import '../styles/globals.css'
import type { AppProps } from 'next/app'
import Header from './main/header'
import { useRouter } from 'next/router'
import {useEffect,useState} from "react"
import GlobalLoading from './components/Loading'
function MyApp({ Component, pageProps }: AppProps) {
const router = useRouter()
const [state, setState] = useState({
isRouteChanging: false,
loadingKey: 0,
})
useEffect(() => {
const handleRouteChangeStart = () => {
setState((prevState) => ({
...prevState,
isRouteChanging: true,
loadingKey: prevState.loadingKey ^ 1,
}))
}
const handleRouteChangeEnd = () => {
setState((prevState) => ({
...prevState,
isRouteChanging: false,
}))
}
router.events.on('routeChangeStart', handleRouteChangeStart)
router.events.on('routeChangeComplete', handleRouteChangeEnd)
router.events.on('routeChangeError', handleRouteChangeEnd)
return () => {
router.events.off('routeChangeStart', handleRouteChangeStart)
router.events.off('routeChangeComplete', handleRouteChangeEnd)
router.events.off('routeChangeError', handleRouteChangeEnd)
}
}, [router.events])
return (
<Header>
<GlobalLoading isRouteChanging={state.isRouteChanging} key={state.loadingKey} />
<Component {...pageProps} />
</Header>
)
}
export default MyApp