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;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/907687.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java-I/O框架09:InputStreamReader、OutputStreamWriter使用

视频链接&#xff1a;16.24 转换流的使用_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1Tz4y1X7H7?spm_id_from333.788.videopod.episodes&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5&p24 1.InputStreamReader使用 package com.yundait.Demo05;import java…

一键AI换衣-可图AI试衣

我们的真的实现了穿衣自由了吗&#xff1f;上传一张人物图片和衣服的图片&#xff0c;就能实现一键换衣。 这就是可图AI试衣项目 魔塔地址&#xff1a;https://www.modelscope.cn/studio ... lors-Virtual-Try-On 参考&#xff1a; 一键AI换衣-可图AI试衣 https://www.jinsh…

Linux的IP网路命令: 用于显示和操作网络接口(网络设备)的命令ip link详解

目录 一、概述 二、用法 1、基本语法 2、常用选项 3、常用参数 4、获取帮助 三、示例 1. 显示所有网络接口的信息 &#xff08;1&#xff09;命令 &#xff08;2&#xff09;输出示例 &#xff08;3&#xff09;实际操作 2. 启动网络接口 3. 停止网络接口 4. 更改…

程序员记笔记有没有必要?如何高效记笔记?

本文转载自&#xff1a;https://fangcaicoding.cn/article/57 大家好&#xff01;我是方才&#xff0c;目前是8人后端研发团队的负责人&#xff0c;拥有6年后端经验&3年团队管理经验&#xff0c;截止目前面试过近200位候选人&#xff0c;主导过单表上10亿、累计上100亿数据…

lust变频器维修电梯变频器CDD34.014.W2.1LSPC1

LUST伺服在安装时须注意&#xff0c;不可有任何的铁屑、螺丝、导线等掉人驱动器内。在安装完成后应作基本的检测动作&#xff0c;如对地阻抗&#xff0c;和短路检测等。 所有的安装及使用事项需要符合安全规定&#xff0c;并且也需要符合当地的相关规定和灾害预防措施。DC BUS…

NFTScan Site:以蓝标认证与高级项目管理功能赋能 NFT 项目

自 NFTScan Site 上线以来&#xff0c;它迅速成为 NFT 市场中的一支重要力量&#xff0c;凭借对各类 NFT 集合、市场以及 NFTfi 项目的认证获得了广泛认可。这个平台帮助许多项目提升了曝光度和可见性&#xff0c;为它们在竞争激烈的 NFT 市场中创造了更大的成功机会。 在最新更…

深度学习在复杂系统中的应用

引言 复杂系统由多个相互作用的组成部分构成&#xff0c;这些部分之间的关系往往是非线性的&#xff0c;整体行为难以通过简单的线性组合来预测。这类系统广泛存在于生态学、气象学、经济学和社会科学等多个领域&#xff0c;具有动态演变、自组织、涌现现象以及多尺度与异质性…

Vue computed watch

computed watch watch current prev

批量提取当前文件夹内的文件名

在需要提取的文件夹内新建一个txt文件&#xff0c;输入&#xff1a; dir ./b>name.txt 然后将该txt文件的扩展名改为.bat 如图 双击即可提取当前文件夹文件名&#xff0c;并保存到name.txt内

Android OpenGL ES详解——模板Stencil

目录 一、概念 1、模板测试 2、模板缓冲 二、模板测试如何使用 1、开启和关闭模板测试 2、开启/禁止模板缓冲区写入 3、模板测试策略函数 4、更新模板缓冲 5、模板测试应用——物体轮廓 三、模板缓冲如何使用 1、创建模板缓冲 2、使用模板缓冲 3、模板缓冲应用——…

QML基础语法2

函数 函数格式&#xff1a; function关键字 函数名(参数名1:参数类型,参数名2:参数类型,...):返回值类型{} 其中&#xff1a; 函数名必须以小写字符开头&#xff0c;后面驼峰可以有多个参数或者没有参数参数类型可以不写返回值类型也可以不写 如何调用&#xff1a;通过id点…

Qt自定义控件:汽车速度表

1、功能 制作一个汽车速度表 2、实现 从外到内进行绘制&#xff0c;初始化画布&#xff0c;画渐变色外圈&#xff0c;画刻度&#xff0c;写刻度文字&#xff0c;画指针&#xff0c;画扇形&#xff0c;画内圈渐变色&#xff0c;画黑色内圈&#xff0c;写当前值 3、效果 4、源…

Rust 力扣 - 1461. 检查一个字符串是否包含所有长度为 K 的二进制子串

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 长度为k的二进制子串所有取值的集合为[0, sum(k)]&#xff0c;其中sum(k)为1 2 4 … 1 << (k - 1) 我们只需要创建一个长度为sum(k) 1的数组 f &#xff0c;其中下标为 i 的元素用来标记字符串中子串…

【2024年11月高质量国际学术会议推荐1】拓展学术视野,点亮学术之路!开启科研新征程!——数学|物理|电离|能源|遥感|交通各大领域...

【2024年11月高质量国际学术会议推荐1】拓展学术视野&#xff0c;点亮学术之路&#xff01;开启科研新征程&#xff01;——数学|物理|电离|能源|遥感|交通各大领域… 【2024年11月高质量国际学术会议推荐1】拓展学术视野&#xff0c;点亮学术之路&#xff01;开启科研新征程&…

沪深A股上市公司数据报告分析

数据分析报 目录 数据分析报告 1.引言 1.1 背景介绍 1.2 报告目的 1.3 报告范围 1.4 关键术语定义 2. 数据收集与预处理 2.1 数据来源概述 2.2 数据收集过程 2.3 数据预处理步骤 3. 数据可视化 3.1分析地区对公司数量的影响 3.2分析行业分类是否影响公…

ImportError: Install xlrd >= 1.0.0 for Excel support

文章目录 一、报错问题二、问题解释三、解决方法 一、报错问题 问题描述&#xff1a; python2.7使用pandas读取excel文件时报错ImportError: Install xlrd > 1.0.0 for Excel support。 问题代码&#xff1a; # codingutf-8import pandas as pddata pd.read_excel(D:\Wo…

【Linux】make/makefile/gdb调试技巧/进度条小程序

目录 一、sudo提权&#xff1a; 二、自动化构建工具make与Makefile makefile&#xff1a; make&#xff1a; 是否重新执行make&#xff1a; 伪目标&#xff1a; 三、进度条小程序&#xff1a; 四、Linux调试器gdb&#xff1a; 1.、前景提要&#xff1a; 2、进入与退出…

Flutter实战短视频课程

1、课程导学 一套代研运行多蜡 体州一致&#xff0c;目胜能优昇 未来大趋势 不改交原生项目的基础上&#xff0c;扩展Flutter能力 Flutter原生灵话切涣 0入侵 最简单、最通用 最新Flutter 3,x新特性讲解 大量flutter官方组件和api学习 最常用的第三方库使用及原理解析 自研组…

程序员的新电脑到手后应该做哪些必要设置?

吃水果要剥皮&#xff0c;用 Windows 也一样&#xff0c;如果是 Win 10 的话&#xff0c;刚装完系统就需要屏蔽一些功能&#xff0c;才能更顺畅快速&#xff1a; 隐藏任务栏上的搜索框和小娜&#xff0c;需要搜索时wins就会出现禁用开始目录的app自动推荐删除人脉图标删除任务…

unocss 添加支持使用本地 svg 预设图标,并支持更改大小

安装 pnpm install iconify/utils 在配置文件 unocss.config.ts&#xff1a; presets > presetIcons 选项中 通过 FileSystemIconLoader 加载本地图标&#xff0c;并指定目录。 import presetWeapp from unocss-preset-weapp import { extractorAttributify, transformer…