React 学习
快速创建一个项目
首先用 vite + react 启动一个 react-ts 项目:
1
2
3
| pnpm create vite [项目名称] --template react-ts
pnpm create vite react-starter --template react-ts
|
添加一些依赖
看自己的喜欢添加一些依赖:
- unocss
- antfu eslint
- lodash-es

删除多余的内容,仅保留 App.tsx 和 main.tsx
组件
组件声明
JSX 必须有一个根节点
可以是 <></>,这是一个 Fragment
所有 HTML 标签必须结束
不管是单标签还是双标签都必须结束:
JSX requires tags to be explicitly closed: self-closing tags like <img> must become <img />, and wrapping tags like <li>oranges must be written as <li>oranges</li>.
大部分 React 的东西都使用驼峰
比如绑定事件:onClick
比如添加 class:className
1
2
3
4
5
6
7
| export default function Page() {
return (
<>
<h1>Home</h1>
</>
)
}
|
导出,用 ES6 语法,导出一个函数返回一个 JSX 片段。
注意:不要在组件内部再去申明一个组件。
注意:React 组件的使用需要开头大写,这样来区分原生的 HTML 标签。
1
2
3
4
5
6
7
| export default function Gallery() {
// 🔴 Never define a component inside another component!
function Profile() {
// ...
}
// ...
}
|
导出和导入组件
可以先看这篇熟悉一下导入导出,是一样的:
ES 导入导出语法
具名导出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| // 导出
export function MyCard(props: { name: string }) { // 接收 props
return <div>{props.name}</div>
}
// 在 page 里导入和使用
import { MyCard } from '../components/MyCard'
export default function Page() {
return (
<>
<MyCard name="Hello" />
</>
)
}
|
默认导出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| // 默认导出
export default function MyButton(props: { text: string }) {
return <button>{props.text}</button>
}
// 默认导入
import MyButton from "../components/MyButton.tsx"
export default function Page() {
return (
<>
<MyButton text="click" />
</>
)
}
|
JSX/TSX 动态插入内容、属性
绑定变量属性
使用 title={name} 的这种形式去给一个标签添加动态的属性:
1
2
3
4
5
6
7
8
9
10
11
12
13
| function App() {
const name = 'foo'
return (
<div title={name}> {/* 使用属性 */}
{name}
</div>
)
}
// 一个花括号里面输入来使用 JS 表达式和变量
// 导出组件
export default App
|
绑定 class
直接添加 class 和绑定 class 的变量:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| function App() {
const myClassName: string = 'w-10 h-10 bg-blue-6'
return (
<> {/* 这里使用了一对空标签当成根标签 */}
{/* 直接绑定 class */}
<div className="w-2"></div>
{/* 绑定 class 变量 */}
<div className={myClassName}></div>
</>
)
}
export default App
|
绑定 style
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| function App() {
const styleObj = {
backgroundColor: 'red',
}
return (
<>
<div style={styleObj}></div>
<div style={{ color: 'red' }}></div>
</>
)
}
export default App
|
总结
动态绑定 class 和 style:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| export default function page() {
const name = 'foo'
const classList = 'w-10 h-10'
const styleObj = {
backgroundColor: 'red',
}
const active = true
const activeClass = `${active ? 'active' : ''}`
return (
<>
<div className={classList}>{name}</div>
<div className="bg-blue-5 w-10 h-10"></div>
<div style={{ background: 'red' }}></div>
<div style={styleObj}></div>
<div className={activeClass}></div>
<div className={`${active}?'active':''`}></div>
<div className={['test'].join(' ')}></div>
</>
)
}
|
事件操作,获取事件对象 event
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| // 事件操作
function App() {
function test(number1?: number, event?: React.FormEvent<HTMLButtonElement>) {
console.log(number1, event)
}
// React.FormEvent<HTMLButtonElement> 是 React 的一些 TS 类型
return (
<div>
{/* 调用方式1 */}
{/* bind 方式拿到 event,默认最后一个参数就是 event */}
<button onClick={test.bind(null, 123)}></button>
{/* 调用方式2 */}
<button onClick={() => {
test(123)
}}></button>
{/* 箭头函数拿到 click 事件对象,箭头函数传参就是 event */}
<button onClick={(event) => {
test(123, event)
}}></button>
</div>
)
}
export default App
|
实现 HTML 循环遍历
使用 map 来返回 JSX 片段:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
| export function mapRender() {
const arr = [1, 2, 3]
const users: userDto[] = [
{
name: 'foo',
age: 18,
},
{
name: 'bar',
age: 19,
},
{
name: 'zhang san',
age: 20,
},
]
interface userDto {
name: string
age: number
}
function UserCard({ user }: { user: userDto }) {
return (
<>
<div>
<h3>
name:
{user.name}
</h3>
<h4>
age:
{user.age}
</h4>
</div>
</>
)
}
return (
<>
<div>
{arr.map((item) => {
return <div key={item}>{item}</div>
})}
</div>
<div>
<ul>
{users.map(user => (
<li key={user.name}>{user.name}</li>
))}
</ul>
</div>
<div>
<ul>
{users.map(user => (
<UserCard key={user.name} user={user} />
))}
</ul>
</div>
</>
)
}
|
动态添加 item
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| export function mapTest2() {
const [items, setItems] = useState(['React', 'Vue', 'Angular'])
const addItem = () => {
setItems([...items, `New Item ${items.length + 1}`])
}
return (
<div>
<button onClick={addItem}>添加项</button>
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
</div>
)
}
|
条件渲染
类似 Vue 的 v-if 渲染:
1
2
3
4
5
6
7
8
9
10
| export function ifTest() {
const [show, setShow] = useState(true)
return (
<div>
<button onClick={() => setShow(!show)}>toggle</button>
{show && <div>show</div>}
</div>
)
}
|
添加内联样式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| // 添加内联样式
const style1 = {
width: '100px',
height: '100px',
backgroundColor: 'lightskyblue'
}
const style2 = {
width: 200
}
/**
* 媒体查询 + 伪类使用 radium 包裹
*/
function App() {
return (
<div>
<div style={{ backgroundColor: 'lightskyblue', width: '100px', height: '50px' }}></div>
<div style={style1}></div>
<div style={{ ...style1, ...style2 }}></div>
</div>
)
}
export default App
|
添加外部 CSS 文件
1
2
3
4
5
6
7
| /* index.css */
.box1 {
width: 100px;
height: 100px;
background-color: lightskyblue;
}
|
1
2
3
4
5
6
7
8
| // 外源 CSS 的使用
function App() {
return (
<div className="box1"></div>
)
}
export default App
|
总结
单个花括号和两个花括号
{}、{{}}
单个花括号
使用场景:
单个花括号的使用场景有且只有在 tag 里面的属性或者是 tag 包裹的内容。
在单个花括号里面开启 JS 的内容:
1
2
3
4
5
6
7
8
9
10
11
| export function test() {
const testClass = 'input-wrapper'
const content = <div>123</div>
return (
<>
<input type="text" className={testClass} />
<div>{content}</div>
</>
)
}
|
两个花括号
绑定内联 CSS:
style 绑定一个对象。
所以其实两个花括号 = JSX 的 JS 域然后里面放一个对象。
等同于我创建一个 obj 然后用单个花括号绑定进去:
1
| <div style={{ width: "100px", height: "100px", backgroundColor: "red" }}></div>
|