React + Vite + TypeScript + React router项目搭建教程

一、创建项目

运行项目

二、目录结构

复制代码
项目目录:
├─node_modules		//第三方依赖
├─public			//静态资源(不参与打包)
└─src
    ├─assets		//静态资源
    ├─components	//组件
    ├─config		//配置
    ├─http			//请求方法封装
    ├─layout		//页面布局
    ├─pages			//页面
    ├─routes		//路由
    ├─service		//请求
    ├─store			//状态管理
    └─util			//通用方法
    └─App.css
    └─App.tsx
    └─index.css
    └─main.tsx
    └─vite-env.d.ts
├─.eslinttrc.cjs
├─.gitignore		
├─index.html		//项目页面总入口
├─package.json	
├─tsconfig.json		//ts配置文件
├─tsconfig.node.json
├─vite.config.ts	//vite配置文件

三、sass安装

1 安装

复制代码
npm i sass -D

2 创建全局 scss 文件

3 引入

这里的additionalData改为

复制代码
additionalData: `@import "./src/assets/styles/index.scss";`

4 修改这4个文件

index.css去掉

main.tsx 中 import './index.css' 去掉

app.css 变成 app.scss,内容只剩下,h1{ color:$red; }

app.tsx 代码如下

复制代码
import './App.scss'

function App() {
  return (
    <>
      <h1>Vite + React</h1>
    </>
  )
}

export default App

sass成功,页面如下

四、写一个函数式组件和类组件

复制代码
import './App.scss'

// 函数式组件写法
// import React, { useState } from 'react';
// function Example() {
//   const [count, setCount] = useState(0);
//   return (
//     <div>
//       <p>You clicked {count} times</p>
//       <button onClick={() => setCount(count + 1)}>
//         Click me
//       </button>
//     </div>
//   );
// }

// 类组件写法
import React from 'react';
class Example extends React.Component<any, any> {
  constructor(props: any) {
    super(props);
    this.state = {
      count: 0
    }
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}

function App() {
  return (
    <>
      <h1>Vite + React</h1>
      <Example></Example>
    </>
  )
}

export default App

五、路由

1 下载

npm install react-router-dom -S

新建3个页面

HashRouter路由(vue中的hash模式)

main.tsx

复制代码
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import { HashRouter as Router } from 'react-router-dom';

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <React.StrictMode>
    <Router>
      <App />
    </Router>
  </React.StrictMode>
)

app.tsx

复制代码
import { Route, Routes, Link, useNavigate } from "react-router-dom";
import Login from "./pages/login";
import Home from "./pages/home";
import User from "./pages/user";
import './App.scss'

function App() {
  const navigate = useNavigate();
  return (
    <div className="App">
      {/* 指定跳转的组件,to 用来配置路由地址 */}
      <Link to="/">首页</Link><br />
      <Link to="/user">用户</Link><br />
      <button onClick={() => navigate('/login')}> 登录 </button>
      <hr />
      {/* 路由出口:路由对应的组件会在这里进行渲染 */}
      <Routes>
        {/* 指定路由路径和组件的对应关系:path 代表路径,element 代表对应的组件,它们成对出现 */}
        <Route path='/' element={<Home />}></Route>
        <Route path='/user' element={<User />}></Route>
        <Route path='/login' element={<Login />}></Route>
      </Routes>
    </div>
  )
}

export default App

成功结果如下

BrowserRouter路由(vue中的history模式?)

main.tsx

复制代码
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import { BrowserRouter as Router } from 'react-router-dom';

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <React.StrictMode>
    <Router>
      <App />
    </Router>
  </React.StrictMode>,
)

app.tsx

复制代码
import { Route, Routes, Link, useNavigate } from "react-router-dom";
import Login from "./pages/login";
import Home from "./pages/home";
import User from "./pages/user";
import './App.scss'

function App() {
  const navigate = useNavigate();
  return (
    <div className="App">
      {/* 指定跳转的组件,to 用来配置路由地址 */}
      <Link to="/">首页</Link><br />
      <Link to="/user">用户</Link><br />
      <button onClick={() => navigate('/login')}> 登录 </button>
      <hr />
      {/* 路由出口:路由对应的组件会在这里进行渲染 */}
      <Routes>
        {/* 指定路由路径和组件的对应关系:path 代表路径,element 代表对应的组件,它们成对出现 */}
        <Route path='/' element={<Home />}></Route>
        <Route path='/user' element={<User />}></Route>
        <Route path='/login' element={<Login />}></Route>
      </Routes>
    </div>
  )
}

export default App

嵌套路由

app.tsx

复制代码
// 嵌套路由
import { Route, Routes, Link, useNavigate } from 'react-router-dom';
import Login from "./pages/login";
import Home from "./pages/home";
import User from "./pages/user";
import './App.scss'
function App() {
  const navigate = useNavigate();
  return (
    <div className="App">
      {/* 指定跳转的组件,to 用来配置路由地址 */}
      <Link to="/home">首页</Link><br />
      <Link to="/home/user">用户</Link><br />
      <button onClick={() => navigate('/home/login')}> 登录 </button>
      {/* 路由出口:路由对应的组件会在这里进行渲染 */}
      <Routes>
        {/* 指定路由路径和组件的对应关系:path 代表路径,element 代表对应的组件,它们成对出现 */}
        <Route path='/home' element={<Home />}>
          <Route path='user' element={<User />}></Route>
          <Route path='login' element={<Login />}></Route>
        </Route>
      </Routes>
    </div>
  )
}
export default App

home.tsx

复制代码
import { Outlet } from "react-router-dom";
function Home() {
    return (
        <div>
            <div>home页面</div>
            <Outlet />
        </div>
    );
}

export default Home;

页面如下

重定向

复制代码
import { Navigate } from 'react-router-dom';
<Route path='/' element={<Navigate to="/layout" />}></Route>

useRoutes路由配置

1 app.scss

复制代码
h1{
  color:$red;
}

body{
  padding: 0;
  margin: 0;
  width: 100vw;
  height: 100vh;
}
#root{
  padding: 0;
  margin: 0;
  width: 100vw;
  height: 100vh;
}

app.tsx

复制代码
import GetRoutes from "./routes/index";
import './App.scss'

function App() {
  return (
    <GetRoutes></GetRoutes>
  )
}
export default App

home.tsx

复制代码
function Home() {
    return (
        <div>home页面</div>
    );
}
export default Home;

新增文件

routes/index.tsx 代码如下

复制代码
import { useRoutes, Navigate, RouteObject } from "react-router-dom";

import Layout from "../layout/index";
import Login from "../pages/login";
import Home from "../pages/home";
import User from "../pages/user";

export const router_item: Array<object> = [
    { path: "/", label: "首页", element: <Navigate to="/layout/home" /> },
    {
        path: "/layout",
        label: "控制台",
        element: <Layout />,
        children: [
            {
                path: "home",
                label: "首页",
                element: <Home />
            },
            {
                path: "login",
                label: "登录页",
                element: <Login />,
            },
            {
                path: "user",
                label: "用户页",
                element: <User />
            },
        ],
    },
];

function GetRoutes() {
    const routes: RouteObject[] = useRoutes(router_item);
    return routes;
}

export default GetRoutes;

layout/index.tsx 代码如下

复制代码
import { Outlet, Link } from "react-router-dom";
function Layout() {
    return (
        <>
            <div style={{display: 'flex', width: '100%', height: '100%'}}>
                <div style={{width: '200px', background: '#eee'}}>
                    <Link to="/layout/home">home 页</Link><br />
                    <Link to="/layout/login">login 页</Link><br />
                    <Link to="/layout/user">user 页</Link><br />
                </div>
                <div style={{flex: '1'}}>
                    <Outlet />
                </div>
            </div>
        </>
    );
}
export default Layout;

页面成功如下

路由懒加载

有些页面比较大,我们可以使用懒加载,来提升页面加载性能,避免页面卡顿;react官网提供了路由懒加载的完整实例:react路由懒加载。懒加载主要借助lazy、suspense组件来实现。

lazy 能够让你在组件第一次被渲染之前延迟加载组件的代码。<Suspense> 允许您显示临时组件(一般是一个loading状态),直到其子项完成加载。

修改 routes/index.tsx 代码如下

复制代码
import { useRoutes, Navigate, RouteObject } from "react-router-dom";

import Layout from "../layout/index";
import Login from "../pages/login";
import Home from "../pages/home";
import User from "../pages/user";

import { lazy } from "react";
import lazyLoad from "./lazyLoad";
// 添加一个固定的延迟时间,以便你可以看到加载状态
function delayForDemo(promise: Promise<any>) {
    return new Promise(resolve => {
        setTimeout(resolve, 2000);
    }).then(() => promise);
}

export const router_item: Array<object> = [
    { path: "/", label: "首页", element: <Navigate to="/layout/home" /> },
    {
        path: "/layout",
        label: "控制台",
        element: <Layout />,
        children: [
            {
                path: "home",
                label: "首页",
                // element: <Home />
                element: lazyLoad(lazy(() => delayForDemo(import("../pages/home")))) //故意延迟2s,这里是延迟加载
            },
            {
                path: "login",
                label: "登录页",
                // element: <Login />,
                element: lazyLoad(lazy(() => import("../pages/login"))),	//这里是延迟加载
            },
            {
                path: "user",
                label: "用户页",
                element: <User />
            },
        ],
    },
];

function GetRoutes() {
    const routes: RouteObject[] = useRoutes(router_item);
    return routes;
}

export default GetRoutes;

增加文件

lazyLoad.tsx 代码如下

复制代码
import { LazyExoticComponent, Suspense } from "react";
import Spinner from "../components/spinner";
/**
 * 实现路由懒加载
 * @param Comp 懒加载组件
 * @returns 
 */
function lazyLoad(Comp: LazyExoticComponent<() => JSX.Element>) {
    return (
        <Suspense fallback={<Spinner />}>
            <Comp />
        </Suspense>
    );
}

export default lazyLoad;

spinner.tsx 代码如下

复制代码
function Spinner() {
    return (
        <>
            loading...
        </>
    );
}

export default Spinner;
相关推荐
热爱编程的小曾24 分钟前
sqli-labs靶场 less 8
前端·数据库·less
gongzemin35 分钟前
React 和 Vue3 在事件传递的区别
前端·vue.js·react.js
Apifox1 小时前
如何在 Apifox 中通过 Runner 运行包含云端数据库连接配置的测试场景
前端·后端·ci/cd
树上有只程序猿1 小时前
后端思维之高并发处理方案
前端
庸俗今天不摸鱼2 小时前
【万字总结】前端全方位性能优化指南(十)——自适应优化系统、遗传算法调参、Service Worker智能降级方案
前端·性能优化·webassembly
黄毛火烧雪下2 小时前
React Context API 用于在组件树中共享全局状态
前端·javascript·react.js
Apifox2 小时前
如何在 Apifox 中通过 CLI 运行包含云端数据库连接配置的测试场景
前端·后端·程序员
一张假钞2 小时前
Firefox默认在新标签页打开收藏栏链接
前端·firefox
高达可以过山车不行2 小时前
Firefox账号同步书签不一致(火狐浏览器书签同步不一致)
前端·firefox
m0_593758102 小时前
firefox 136.0.4版本离线安装MarkDown插件
前端·firefox