Skip to content

Commit

Permalink
docs: 更新 TypeScript 文档,添加泛型类型和any类型的介绍
Browse files Browse the repository at this point in the history
添加了关于 TypeScript 的泛型类型和 any 类型的介绍,以及相应的示例代码。
  • Loading branch information
ZtfCoder committed Oct 20, 2024
1 parent d5d040e commit 581e4a1
Show file tree
Hide file tree
Showing 5 changed files with 222 additions and 27 deletions.
170 changes: 143 additions & 27 deletions docs/main/react/5-react组件数据流.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,55 +3,164 @@ title: react 第5节
description: react props
---

## props
## 父子组件

在实际开发中,一个页面的代码非常多,随着项目继续开发,页面的代码会越来越多,导致维护困难,在这个时候,我们通常会把一个页面的代码拆分到不同的`jsx`文件中, 这些`jsx` 文件,我们统称为组件

![alt text](ts/image4.png)

可以看到,我们把页面拆分成了 4 个组件,每个组件都是独立的`jsx` 文件

这样方便我们不同的人在一个页面进行独立开发,开发完后,再统一合并到一个`jsx` 文件中,最终组成了我们的页面

其中 最终合并的 jsx 文件 我们叫`父组件`, 例如上图中,组件 1,组件 2,组件 3,组件 4 我们统称为 这个父组件的 子组件,拥有父子关系

以下是父子组件的用例

```jsx
// 这是我们的页面组件
import { useState } from "react";
import Header from "./components/Header";
import UserList from "./components/UserList";
import Footer from "./components/Footer";
const Page = () => {
const [title, setTitle] = useState("这是标题");
const [userList, setUserList] = useState(["zs", "ls", "ww"]);
return (
<div>
<Header></Header>
<UserList></UserList>
<Footer></Footer>
</div>
);
};
return Page;
```

在 Page 组件中,我们引入了 3 个组件 `Header`,`UserList`,`Footer`,这 3 个组件,就是 Page 的子组件,而 Page 就是`Header`,`UserList`,`Footer`这 3 个组件的父组件

props 是用于在不同组件传递数据的词
写法是
在 Page 组件的 jsx 文件目录下创建`components` 目录,用于存放 Page 组件的子组件
然后创建`Header`,`UserList`,`Footer`这 3 个组件

```jsx
const Header = () => {
return <div>这里是 Header</div>;
};
return Header;
```

// props通常是用写成一个对象的形式
const UserList = (props)=>{
```jsx
const UserList = () => {
return <div>这里是 UserList</div>;
};
return UserList;
```

```jsx
const Footer = () => {
return <div>这里是 Footer</div>;
};
return Footer;
```

## props

一个页面,是有不同的数据渲染出来的,上面我们拆分了 Page 页面成三个独立的组件,我们如何才能把`Page` 页面的数据传递给我们的子组件呢,此时就需要使用 `react` 提供的 `props` 功能,所谓 props 就是用于把父组件的数据,传递给子组件,在上面的案例,我们需要把 `title` 传递给 `Header` 组件,把`userList` 传递给 `UserList` 组件

首先我们需要在我们的子组件中声明我们这个组件是需要接受外部传递数据的,写在`UserList`函数的参数上,通常是写成 `props` 这个名字,

```jsx
const Header = (props) => {
// 一般我们在组件内使用解构的形式获取对象中的值(只是习惯,也可以不按照这样)
// 假如 props 中有 name和age
const { name,age } = props
const { title } = props; // 从props 中 获取由父组件传递过来的数据,名字叫title
// 省略内容
return (
<div>name:{name}</div>
<div>age:{age}</div>
)
}

return <div>title:{title}</div>; // 把title 渲染到页面上面
};
```

其中函数式组件的参数就是我们的 props,其他组件想要传递则需要按照以下格式

```jsx
// 这里是另外一个页面,引入我们写好的组件
// 这是我们的页面组件
import { useState } from "react";
import Header from "./component/Header";
import UserList from "./component/UserList";
import Footer from "./component/Footer";
const Page = () => {
return <UserList name={"hxg"} age={18} />;
const [title, setTitle] = useState("这是标题");
const [userList, setUserList] = useState(["zs", "ls", "ww"]);
return (
<div>
<Header title={title}></Header> {/* 在这里用,我们把title 传递给子组件 */}
<UserList></UserList>
<Footer></Footer>
</div>
);
};
return Page;
```

这里需要注意,子组件中的 props 变量是不可更改的,不能去修改子组件的 props 值,只能在父组件修改
回到页面就可以看到父组件中的值,在子组件中给渲染出来了

这里需要注意,子组件中的 props 变量是不能在组件进行更改的,不能去修改子组件的 props 值,我们只能通过父组件的函数进行修改

props 中可以传递任何值,也可以传递一个函数进来

```jsx
import { useState } from "react";
import Header from "./component/Header";
import UserList from "./component/UserList";
import Footer from "./component/Footer";
const Page = () => {
const handleClick = () => {
alert("这是父组件 Page 的方法");
const [title, setTitle] = useState("这是标题");
const [userList, setUserList] = useState(["zs", "ls", "ww"]);

const handleChangeTitle = (title) => {
setTitle(title);
};
return <UserList name={"hxg"} age={18} handleClick={handleClick} />;

return (
<div>
<Header title={title} updateTitle={handleChangeTitle}></Header> {/* 在这里用,我们把handleChangeTitle 传递给子组件 */}
<UserList></UserList>
<Footer></Footer>
</div>
);
};
return Page;
```

然后修改子组件的参数,

```jsx
const Header = (props) => {
// 一般我们在组件内使用解构的形式获取对象中的值(只是习惯,也可以不按照这样)
const { title, updateTitle } = props; // 从props 中 获取由父组件传递过来的数据,名字叫title,这里的updateTitle 就是父组件传递过来的handleChangeTitle

// 省略内容
return (
<div>
title:{title}
<button onClick={() => updateTitle("hxg")}>请点击更改</button>
</div>
); // 把title 渲染到页面上面
};
```

这里可以看到我们虽然在父组件里写的是 `updateTitle={handleChangeTitle}`
但是在子组件我们这个函数的名字是`updateTitle` 所以,props 的名称,不一定要和变量名称一致

此时我们点击按钮,就会触发 `updateTitle``updateTitle` 实际上是父组件的`handleChangeTitle` 这个函数,所以触发`updateTitle`的本质上是触发了`handleChangeTitle` 这个函数

注意 props 可以无限传递,可以传递给子组件的子组件 但是比较繁琐,对于这种情况 react 有解决方案,后续会讲

需要注意的是,如果在父组件内使用了 setXXX 的 useState 函数时,父组件重新渲染,子组件也会重新渲染
练习下,把 把父组件的`userList` 变量传递给 `UserList` 组件,进行渲染

可以自己练习下,在父组件传递参数到子组件,然后再通过点击事件修改传递到子组件的 props
::: warning 提示
我们知道当组件内调用 setXXX 的时候会使页面重新渲染,也就是让函数组件重新执行一次,
如果在父组件内使用了 setXXX 的 useState 函数时,父组件重新渲染的同时,子组件也会重新渲染,
但是如果子组件进行 setXX 的时候,并不会触发父组件的渲染
:::

## 组件嵌套

Expand All @@ -65,8 +174,10 @@ const Page = () => {
```jsx
const Page1 =()=>{
return (
<Header title="页面1" />
<User />
<>
<Header title="页面1" />
<User />
<>
)
}
```
Expand All @@ -76,8 +187,11 @@ const Page1 =()=>{
```jsx
const Page2 =()=>{
return (
<Header title="页面2" />
<User />
<>
<Header title="页面2" />
<User />
<>

)
}
```
Expand All @@ -87,8 +201,10 @@ const Page2 =()=>{
```jsx
const Page2 =()=>{
return (
<Header title="页面3" />
<User />
<>
<Header title="页面3" />
<User />
<>
)
}
```
Expand Down
37 changes: 37 additions & 0 deletions docs/main/react/6-typescript.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
---
title: react和typescript第一节
description: react typescript
---

## 什么是 typescript

::: warning 提示
Expand Down Expand Up @@ -177,3 +182,35 @@ age = "18"; //ts 不报错
age = 18; // ts 不报错
age = null; // ts 报错,因为只允许 字符串或者数字类型
```

## 泛型类型

`ts`的泛型 和`Java`的泛型是一样的意思,泛型一般是写在函数的参数上,或者给类型 type 或者 interface 上使用

```ts
const fun = <T, R>(p1: T, p2: R) => {
console.log(p1, p2);
};
```

这里定义了一个函数 fun,函数有个参数,p1 和 p2,参数的类型是由外部决定的,例如,我如果要使用 fun 的话,就需要一下写法

```ts
fun<string, number>("1", 2);
```

这样就表示,此时 fun 的第一个参数是 string 类型,第二个参数为 number 类型,如果我们都传入`"1"` 字符串的 1,则会提示类型错误

通常,很少需要我们自己去定义泛型,很多时候都是使用别人写好的函数,而这个函数,需要自己定义参数类型,例如`react` 中的`useState` 则是需要自己定义存储的是什么类型的数据,`useMemo` 也是同理

## any 类型

any 是 ts 最大的类型,使用 any 类型,可以无视 ts 的其他类型检测,尽量少使用 any 类型,如果使用 any 类型,就和跟没有 ts 的一样的意思

```ts
const fun = (age: any) => {};
```

声明 any 后,ts 会无视传入的类型

## as 语法
42 changes: 42 additions & 0 deletions docs/main/react/7-typescript和react.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
title: react和typescript第二节
description: react typescript
---

前面一章,我们学了 typescript,这章我们把 typescript 与 react 结合起来,

## 搭建项目

首先在一个空文件夹下面 打开 cmd

```shell
npm create vite@latest

```

接着等待一会后,会出现 第二节的脚手架 一样的流程输入

1. 首先输入项目名称 回车
2. 选择 `react` 框架 回车
3. 选择`typescript` 第一个选项 回车

进入到新创建项目文件夹内,打开 cmd 执行 `npm i` 进行安装依赖

用 vscode 打开后,可以看到,基本和我们之前创建的是一样的,但是多了些其他内容
![alt text](ts/image3.png)

可以看到我们以前的`jsx` 文件变成了`tsx`, 这个就是 react 和 typescript 的结合文件

vite-env.d.ts : 这是 vite 自带的 ts 类型,里面有一些全局使用的类型

tsconfig.app.json:`typescript` 的配置文件,我们不用管,默认的就够用

ts.config.json :`typescript` 的配置文件,我们不用管,默认的就够用

ts.node.json :`typescript` 的配置文件,我们不用管,默认的就够用

::: warning 提示
只要是 typescript 项目,以前创建的`jsx` 文件,现在需要改成`tsx` 后缀,
`js` 后缀文件,需要改成`ts` 后缀文件

:::
Binary file added docs/main/react/ts/image3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/main/react/ts/image4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 581e4a1

Please sign in to comment.