创建react项目
npm create vite
之后选择框架 react,之后选择自己熟悉的语言,之后的项目构建使用的是TypeScript
cd react-app //进入项目目录
npm i //安装第三方依赖
npm run dev //启动本地服务器
编译项目
npm run build
yarn build
启动开发服务器
npm run dev
这是项目的“心脏”,你写的代码和资源都在这里。src 是“source”(源代码)的缩写。
assets:放静态资源,比如图片、字体这些东西
components:常用命名习惯。存放一个个组件。组件相当于一个功能,比如一个按钮、一个消息框
vite-env.d.ts:vite-env.d.ts 是一个专门用来声明 Vite 项目中环境类型定义的文件。通常,Vite 项目会自动生成这个文件,并默认包含这行指令。
这个文件初始的代码
/// <reference types="vite/client" />
这行代码的主要目的是让 TypeScript 能够识别和使用 Vite 在客户端(client-side)提供的类型定义。vite/client 是 Vite 内置的一个类型声明文件,里面包含了 Vite 在客户端运行时提供的全局变量、函数和模块的类型信息。
这个文件夹放了一些不会被代码加工的文件,比如图片、图标或者 HTML 模板,这些是“静态”的东西。
<!DOCTYPE html> //声明这是一个 HTML5 文档
<html lang="en"> //lang="en" 表示页面语言为英语。
<head> //标签包含页面的元数据和外部资源
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" /> //设置浏览器标签页的图标(favicon),这里使用 Vite 的 SVG 图标
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> //控制移动设备上的视口,使页面宽度适配设备屏幕,默认缩放比例为 1。
<title>Vite + React + TS</title> //定义浏览器标签页的标题,这里是 “Vite + React + TS”
</head>
<body> //标签包含页面的可见内容和脚本加载逻辑
<div id="root"></div> 一个空的 <div> 元素,ID 为 root,是 React 应用的挂载点
<script type="module" src="/src/main.tsx"></script> //引入 React 应用的入口文件 /src/main.tsx,并以 ES 模块方式加载。
</body>
</html>
import React from 'react' // 导入了 React 库,它提供了创建组件、使用 JSX 语法以及管理虚拟 DOM 的能力
import ReactDOM from 'react-dom/client' // ReactDOM 库的 client 模块,ReactDOM 是 React 和浏览器 DOM(文档对象模型)之间的桥梁。createRoot 方法来自这个模块,用于创建 React 应用的根节点,从这里开始渲染组件。
import App from './App' //App 是应用的根组件,包含了整个应用的结构和逻辑,其他子组件会嵌套在其中。这个是我们后续完善单个组件融合之后的子集合文件。
import 'bootstrap/dist/css/bootstrap.css' //Bootstrap 的 CSS 文件
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)
Bootstrap 是一个流行的 CSS 框架,提供了预定义的样式类(比如按钮、网格、表单等),导入后可以在项目中直接使用这些样式来美化界面。
安装命令
npm i bootstrap@5.2.3
我们这里将原来的 index.css 文件删除了。组件使用预定义好的css样式。
这是一个根组件文件,Button 和 Alert 是两个子组件。
import Button from "./components/Button";
import Alert from "./components/Alert";
import { useState } from "react"; //React 提供的一个 Hook,专门用于在函数组件中管理状态(state)
function App() {
const [alert,setalert] = useState(false);
return (
<div>
{alert && <Alert onClose={() => setalert(false)}>My alert</Alert>}
<Button color = "secondary" onClick={() => setalert(true)}>MY Button</Button>
</div>
);
}
export default App;
const [alert,setalert] = useState(false);
它返回一个数组,数组中有两个元素,第一个元素是状态变量(这里是 alert),表示当前的状态值。第二个元素是更新状态的函数(这里是 setAlert),用于修改状态变量的值。
这里定义了一个状态变量 alert,它的初始值被设置为 false,setAlert 是一个函数,通过调用它可以更新 alert 的值。就比如 onClick={() => setalert(true)}
,我们向 setalert 函数传入true参数来更改 alert 的值
这一个列表功能的组件。我们这里只定义了组件的逻辑,而参数是通过接口 Props 传入的。
import { Fragment, useState } from "react";
interface Props {
items : string[];
heading: string;
onselect:(item: string) => void
};
function ListGroup({items,heading,onselect}:Props) {
//Hook
const [selectedIndex, setSelectedIndex] = useState(-1);
const handleSelectItem = (item : string) => {
console.log(item);
}
const getMessage = () => {
return items.length === 0 ? <p>No item found</p> : null;
};
return (
<>
<h1>{heading}</h1>
{items.length === 0 && <p>No item found</p>}
<ul className="list-group">
{items.map((item, index) => (
<li
className={
selectedIndex === index
? "list-group-item active"
: "list-group-item"
}
key={item}
onClick={() => {
setSelectedIndex(index);
onselect(item)
}}
>
{item}
</li>
))}
</ul>
</>
);
}
export default ListGroup;
className命名
在 React 中,要给 HTML 元素添加 CSS 类,必须使用 className,而不是 HTML 中的 class。这是因为 class 是 JavaScript 的保留关键字,在 React 的 JSX 语法中会引起冲突, class 不是有效的属性。
{items.length === 0 && <p>No item found</p>}
Fragment 的用法
Fragment 允许你将多个元素分组,而不在 DOM 中添加额外节点。一个组件return只能返回一个节点,节点也就是指元素:如 <div>、<h1>、<p> ,或者是文本节点<ul>等。相比使用<div>来包裹返回一个对象,使用 <Fragment></Fragment> 或者简写为 <></>。使用 <div> 作为根元素时,会在最终的 DOM 树中多出一个 <div> 节点,而使用 Fragment(可以用 <>...</> 表示)时,不会生成额外的节点。最终只会返回下面的结构
<h1>标题</h1>
<p>内容</p>
map方法
map 方法的作用是将 items 数组中的每个字符串转换为一个带有动态样式和点击事件的 li 元素,并将这些元素组合成一个列表渲染到页面。自动遍历数组里面的元素。
key 属性的作用
在 React 中,当你用 map 方法渲染一个列表时,比如显示一组数据,React 需要知道每个列表项的“身份”。key 就是一个唯一的标识符,帮助 React 高效地追踪和管理这些列表项。
假设待办事项是这样的
const items = ["买牛奶", "写作业", "打扫房间"];
用户把“打扫房间”移到第一位,列表变成:
const items = [ { id: 3, text: "打扫房间" }, { id: 1, text: "买牛奶" }, { id: 2, text: "写作业" } ];
React 看到 key=3 跑到第一位,key=1 和 key=2 跟着调整位置。它知道这些项只是换了顺序,不会重新渲染内容,而是直接移动现有的 DOM 节点,结果是:
- 打扫房间 (key=3) - 买牛奶 (key=1) - 写作业 (key=2)
如果不使用key
React 会认为:
结果是 React 可能会重新更新所有项的内容,而不是简单地调整顺序,这样效率很低。 避免问题:如果列表项有状态(比如输入框),key 确保状态跟正确的项绑定,不会错乱
import React, { ReactNode } from "react";
interface Props {
children: ReactNode;//表示 Alert 组件可以接受子元素。
onClose: () => void;//表示 Alert 组件接受一个名为 onClose 的函数
}
const Alert = ({ children, onClose }: Props) => {
return (
<div className="alert alert-primary d-flex justify-content-between align-items-center">
<span>{children}</span>
<button
type="button"
className="btn-close"
data-bs-dismiss="alert"
data-bs-target="#my-alert"
aria-label="Close"
onClick={onClose} // 将 onClick 移到按钮上
></button>
</div>
);
};
export default Alert;
这里规定了参数的格式。接口 Props 定义了 Alert 组件所接受的 props 的类型
children: ReactNode
当使用 TypeScript 开发 React 组件时,为了确保代码的类型安全,必须为组件的 props 定义类型。如果不给 children 指定类型,TypeScript 无法推断它是什么,可能会导致类型错误,或者 IDE 无法提供准确的代码提示。因此,显式声明 children 的类型是必要的
ReactNode 是 React 提供的一个类型别名(type alias),它描述了 React 组件可以接受的所有可能的 children 类型。具体来说,ReactNode 包括:
className="btn-close"
这里的样式是Bootstrap提供的。
import React from "react";
interface Props {
children: string;
onClick: () => void;
color: string;
}
const Button = ({ children, onClick, color }: Props) => {
return (
<button className={"btn btn-" + color} onClick={onClick}>
{children}
</button>
);
};
export default Button;
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!