Front End Learning Notes

Front End Learning Notes

Vue 和 React的区别

考点在于React的 虚拟Dom

Hooks

what is hook?

常用hook

useState

useEffect

useContext

useReducer

useCallback

useMemo

useRef

useLayoutEffect

useImperativeHandle

useDebugValue

自定义hook,并使用

What is SSR

如何防范SSR

快速上手React的Demo

用脚手架 快速初始化

1
npx craete-react-app my-react-app
1
cd my-react-app

启动项目

1
npm start

明确项目分布情况

源代码 src 目录

静态页面资源 public

关键文件

src下面的,

index 项目入口文件

该文件两个重要引入 React 和 ReactDOM

主要是通过 ReactDOM.createRoot方法 创建实例

通过render进行渲染

根组件 APP.js

react的组件就是函数组件形式(也有类组件,但是不推荐)

JSX 只能返回一个元素

变量插入值不是双引号内,而是{}内

1
2
3
4
5
6
7
8
9
10
function App() {

const divContent = "content"
const divTitle = "title"

return (
<div title ={divTitle}>{divContent}</div>
);
}
export default App;

条件插入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function App() {

const divTitle = "title"
const flag = true;
let divContent = null

if (flag) {
divContent = <p>flag为true</p>
} else {
divContent = <span>flag为false</span>
}
return (
<div title ={divTitle}>
{divContent}
</div>
);
}
export default App;

遍历 list.map

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

function App() {

const list = [
{ id: 1, name:'x1'},
{ id: 2, name:'x2'},
{ id: 3, name:'x3'}
]
const listContent = list.map(item => (
<li key={item.id}>{item.name}</li>
))

return (
<div >{listContent}
</div>
);
}
export default App;

Fragment 每次增加其他行

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
import { Fragment } from "react";

function App() {

const list = [
{ id: 1, name:'x1'},
{ id: 2, name:'x2'},
{ id: 3, name:'x3'}
]


const listContent = list.map(item => (
<Fragment>
<li key={item.id}>{item.name}</li>
<li>----------------</li>
</Fragment>
))

return (
<div >{listContent}
</div>
);
}

export default App;

事件操作 和 setContent

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { useState } from "react";

function App() {

let divContent = "Default Content"

function handle(e) {
console.log("press the button: ", e)
setData("new Content")
}

const [data, setData] = useState("Default content")

return (
<>
<div>{data}</div>
<button onClick={handle}>button</button>
</>
);
}

export default App;

…data

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
import { useState } from "react";

function App() {

let divContent = "Default Content"

function handle(e) {
setData({
...data,
content: "new content"
})
}

const [data, setData] = useState({
title: "default title",
content: "default content"
})

return (
<>
<div title={data.title}>{data.content}</div>
<button onClick={handle}>button</button>
</>
);
}

export default App;

增加元素

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
import { useState } from "react";

function App() {

let divContent = "Default Content"

const [data, setData] = useState([
{ id: 1, name:'x1'},
{ id: 2, name:'x2'},
{ id: 3, name:'x3'}
])

const listData = data.map(item => (
<li key={item.id}>{item.name}</li>
))

let id = 3;

function handle() {
setData([
{id: ++id, name: "cat"}, // 前面加
...data,
// {id: ++id, name: "cat"} 后面加
])
}

return (
<>
<ul>{listData}</ul>
<button onClick={handle}>button</button>
</>
);
}

export default App;

过滤功能filter

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
import { useState } from "react";

function App() {

let divContent = "Default Content"

const [data, setData] = useState([
{ id: 1, name:'x1'},
{ id: 2, name:'x2'},
{ id: 3, name:'x3'}
])

const listData = data.map(item => (
<li key={item.id}>{item.name}</li>
))


function handle() {
setData(data.filter(item => item.id != 2))
}

return (
<>
<ul>{listData}</ul>
<button onClick={handle}>button</button>
</>
);
}

export default App;

自定义图片格式

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
import { useState } from "react";
import image from './logo.svg'
function App() {

// const imageStyle = {
// width: 100,
// height: 100,
// backgroundColor: "grey"
// }

const imgData = {
className: "small",
style : {
width: 100,
height: 100,
backgroundColor: "grey"
}
}

return (
<div>
<img
src={image}
alt=""
{...imgData}
>
</img>
</div>
);
}

export default App;

传入参数式生成多个对象

请求功能所需的数据(例如文章信息) 创建 Article 组件进行遍历
将文章的数据分别传递给 Article

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
function Article(props) {
return (<div>
<h2> {props.title}</h2>
<p>{props.content}</p>
</div>)
}

function App() {

return (
<>
<Article
title="title1"
content="content1"
/>
<Article
title="title2"
content="content2"
/>
<Article
title="title3"
content="content3"
/>
<Article
title="title4"
content="content4"
/>
</>
);
}

export default App

解构方式,简化上述写法 + 层嵌套

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

function Detail({content, active}){
return (
<>
<p>{content}</p>
<p>state: {active ? "showing" : "hidden"}</p>
</>
)
}
function Article({title, articleData}) {
return (<div>
<h2> {title}</h2>
<Detail {...articleData}/>
</div>)
}
function App() {
const articleData = {
title: "title1",
detailData: {
content: "content1",
active: true
}
}
return (
<>
<Article {...articleData}/>
</>
);
}
export default App;

父组件向子组件进行数据传递

注意 传递过去的数据都是 仅可读的,不可以修改

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

function List({ title, children, footer = <div>default bottom</div> }){
return (
<>
<h2>{title}</h2>
<ul>{children}</ul>
{footer}
</>
)
}

function App() {
return (
<>
<List
title="list1"
footer={<p>This the bottom content</p>}
>
<li>list item1</li>
<li>list item2</li>
<li>list item3</li>
</List>
<List
title="list2"
>
<li>list itemA</li>
<li>list itemB</li>
<li>list itemC</li>
</List>
</>
);
}
export default App;

子组件向父组件传递

涉及到 回调函数

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
import { useState } from "react";

function Detail({onActive}) {
const [status, setStatus] = useState(false)

function handle(){
setStatus(!status)
onActive(status)
}

return(
<div>
<p style={{
display: status ? "block" : "none"
}}>Detail的内容</p>
<button onClick={handle}> button</button>
</div>
)
}

function App() {

function handleActive (status){
console.log(status)
}

return (
<>
<Detail
onActive={handleActive}
/>
</>
);
}
export default App;

同级组件传值, 借助 父组件进行中转

多层级组件传播,借助hooks

快速上手 JavaScript

下面是一个点击生成新的内容的快速展示

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.change{
width: 100px;
line-height: 100px;
background-color: red;
color: white;
text-align: center;
transition: all 1s;
}
</style>
</head>
<body>
<div id="box">default content</div>
<script>
box.onclick = function (){
this.innerText = "new Content"
this.className = "change"
}
</script>
</body>
</html>

拆为两个文件

1
2
3
4
5
<body>
<div id="box">default content</div>
<script src="quicklearn.js">
</script>
</body>

文件名为 quicklearn.js

1
2
3
4
5
6
<script>
box.onclick = function (){
this.innerText = "new Content"
this.className = "change"
}
</script>

image-20231116232522368

基本语法

1
2
3
4
5
6
// name
var num = 10
var myAge = 18
var num1 = 20
var num2 = 30
// var myFriend
1
2
3
4
5
6
// data type
var myNum = 10 //number
var myStr = 'text' // string
var myBool = true // boolean
var myNull = null // Clear variable content
var myUn // undefined, the default value
1
2
3
4
5
6
7
8
9
// operator
var sum = 1 - 2 * 3 / 4

var resStr = "hello" + "javaScript"

var isTrue = 21 > 3

// compare two items
console.log(2 === 2)
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
// statement
if (2 > 3) {
console.log("i will execute")
} else if (false) {
console.log("i won't execute")
} else {
console.log("rest")
}

var sum = 0;
for (var i = 0; i < 10; i++) {
sum += i
console.log(i)
}
console.log(sum)


function getSum(start, end){
var sum = 0;
for (var i = start; i <= end; i++) {
sum += i
}
return sum
}
var res2 = getSum(100, 200)
console.log(res2)



//Nested functions
function getSum2(start, end, fn){
var sum = 0;
for (var i = start; i <= end; i++) {
if(fn(i)) sum += i
}
return sum
}

var res3 = getSum2(1, 100, function (n) {
if (n % 2 === 0) {
return true
}
return false
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// array
var myArr = [10,20,30,40,50]
console.log(myArr.length)
console.log(myArr[0])
console.log(myArr[1])
console.log(myArr)

// add element from end
myArr.push(100)
// from start
myArr.unshift(200)
console.log(myArr)

// for each
myArr.forEach(function (item, index) {
console.log(item, index)
})
1
2
3
4
5
6
7
8
9
10
11
// Object 
var obj = {
name: "joe",
age: 1
}
console.log(obj)
console.log(obj.name)

for (var k in obj) {
console.log(k, obj[k])
}

DOM 和 BOM

DOM叫做文档对象模型

BOM叫做浏览器对象模型

获取id,修改页面内容

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="block">default content</div>
<p>default content</p>
<p>default content</p>
<p>default content</p>
<p>default content</p>

<script>
var block = document.getElementById('block')
console.log(block)
block.textContent="JS set content"

var contents = document.getElementsByTagName('p')
console.log(contents)

// contents[0].textContent = "the firsrt p title"
var textArr = [
'震山的虎',
'敏捷的豹',
'远见的鹰',
'善战的狼'
]

for(var i = 0; i < contents.length; i++) {
// contents[i].textContent = "new Content"
contents[i].textContent = textArr[i]
}


</script>
</body>
</html>

采用document

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="block">default content</div>
<div id="container">
<p>default content</p>
<p class="item">default content</p>
<p>default content</p>
<p>default content</p>
</div>
<script>
var block = document.getElementById('block')

var contents = document.querySelectorAll('#container p')
console.log(contents)

var textArr = [
'震山的虎',
'敏捷的豹',
'远见的鹰',
'善战的狼'
]
for (var i = 0; i < contents.length; i++) {
contents[i].textContent = textArr[i]
}

// 只具备单个item
var secondItem = document.querySelector('.item')
secondItem.textContent = '替罪的羊'

// 前一个同级别的元素
secondItem.previousElementSibling.textContent = '划水的鱼'
// 后一个同级别的元素
secondItem.nextElementSibling.textContent = '装饭的桶'


// 父元素
var container = secondItem.parentElement
console.log(container)
// container.textContent = '新内容' // 替换所有的话

var items = container.children
console.log(items)


</script>
</body>
</html>

image-20231117173219033

样式处理

下面是通过DOM修改block的样式

一共是两种方式

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
body {
margin: 10px;
}
div {
width: 100px;
height: 100px;
border: 1px dashed #ccc;
margin-bottom: 10px;
}


.changesStyle{
width: 80px;
height: 80px;
background-color: tomato;
}

</style>
</head>
<body>
<div id="block">default content</div>
<script>
// 样式处理
var block = document.querySelector('#block')
// block.style.width = '80px'
// block.style.height = '80px'
// block.style.backgroundColor = 'tomato';// 修正属性名和颜色值
block.className = 'changesStyle'
</script>
</body>
</html>

文本处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 <head>
<style>
.bold-text {
font-size: 20px;
font-weight: 700;
}

</style>
</head>
<body>
<div id="block">default content</div>
<script>
// 样式处理
var block = document.querySelector('#block')
// 文本处理
block.innerHTML = "普通内容<span class='bold-text'>加粗文本</span>"
</script>

事件处理

原始方式

1
2
3
4
var block = document.querySelector('#block')
block.onclick = function () {
alert("surprise again")
}

新版, 相比原版,可以处理多个 点击事件

1
2
3
4
5
6
7
8
9
var block = document.querySelector('#block')
// 事件处理
block.addEventListener('click', function () {
alert('suprise!')
})

block.addEventListener('click', function () {
alert("surprise again!")
})

网络请求

什么是网络请求

网络资源 从服务器 传送到 本地客户端

这样我们就能看到网页的内容了。

这每次一的传输就 是 网路请求。

网络请求方式

ajax

第三方工具 和 fetch API(替代ajax)

ajax

前端发送请求给后端

get例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// or ajax

const xhr = new XMLHttpRequest()
xhr.open('GET', 'http://wuyou.com/common/get?name=wuyou&age=18')
xhr.send()

// 根据状态,触发function 改变
xhr.onreadystatechange = function () {
// response 完成
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
console.log(xhr.responseText)
console.log(JSON.parse(xhr.responseText))
}
}

get只能发纯文本数据

post可以发送各种各样的格式的数据

比如 图片, 视频等

要添加 发送给 服务器的数据是什么类型

post发送的参数在 send()中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const xhr = new XMLHttpRequest()
xhr.open('POST', 'http://wuyou.com/common/post')
// url-encoded 格式
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
xhr.send('name=wuyou&age=18')

// 根据状态,触发function 改变
xhr.onreadystatechange = function () {
// response 完成
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
console.log(xhr.responseText)
console.log(JSON.parse(xhr.responseText))
}
}

Axios

使用第三方工具包简化 请求

下面以Axios为例子

1
npm install axios
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
const { default: axios } = require("axios");


// axios
// axios.get("http://wuyou.com/common/get?name=吴悠&age=18")
(async() => {

// configure base address
const ins = axios.create({
baseURL: "http://wuyou.com/common/"
})

// 配置拦截器

// 请求拦截器
ins.interceptors.request.use(config => {
console.log("发送了请求")
return config
})

ins.interceptors.response.use(res => {
return res
})

// 响应拦截器
const res = ins.get("get", {
params: {
name: 'wuyou',
age: 18
}
})

const res2 = await ins.post("post", {
name: 'wuyou',
age: 18
})

console.log(res1.data)
console.log(res2.data)
})

Fetch API

Fetch API

用来 代替原来的AJAX

1
npm install node-fetch

get请求

1
2
3
4
5
6
7
8
9
10
11
12

const fetch = require('node-fetch');

fetch("http://wuyou.com/common/get?name=wuyou&age=18")
.then(res => {
if (res.ok) {
return res.json()
}
})
.then(data => {
console.log(data)
})

POST请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

const fetch = require('node-fetch');

fetch("http://wuyou.com/common/post", {
method: 'POST',
headers: {
'Content-Type' : 'application/json'
},

// 将2javascript格式转为JSON
body: JSON.stringify({
name: 'wuyou',
age: 18
})

})
.then(res => {
if (res.ok) {
return res.json()
}
})
.then(data => {
console.log(data)
})

异步编程

Promise

将 异步 变为 同步, 返回数据

因为 前端 向 后端 发送请求之后, 需要等待一定时间,如果直接调用,会返回undefine

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

function one(){
return 'I am One'
}

function two(){
setTimeout(() => {
return 'I am Two'
}, 3000) // 3s后返回

}
function three(){
return 'I am Three'
}

function run() {
console.log(one())
console.log(two())
console.log(three())
}
run()

image-20231117153851937

undefined是因为two函数没return,里面的return是settimeout的回调函数的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function one(){
return 'I am One'
}

function two(){
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("I am two")
})
})
}
function three(){
return 'I am Three'
}

function run() {
console.log(one())
console.log(two())
console.log(three())
}
run()

image-20231117154546035

添加async 调用 和 await等待

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function one(){
return 'I am One'
}

function two(){
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("I am two")
})
})
}
function three(){
return 'I am Three'
}

async function run() {
console.log(one())
console.log(await two()) // 等two() 执行完后,在进行three()
console.log(three())
}
run()

上面是解释Promise基本,下面是Poromise常用基本语法

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
//下面是 js 中 Promise 对象的基本用法
//创建一个 Promise 对象:
const promise = new Promise((resolve, reject) => {
// 异步操作
// 如果操作成功,调用 resolve 并传递结果值
// 如果操作失败,调用 reject 并传递错误信息
});

//使用 Promise 对象的 then() 方法处理操作成功的情况:
promise.then((result) => {
// 处理操作成功的情况,result 为操作的结果值
});

//使用 Promise 对象的 catch() 方法处理操作失败的情况:
promise.catch((error) => {
// 处理操作失败的情况,error 为错误信息
});

//可以链式调用 then() 方法,处理多个异步操作的情况:
promise
.then((result1) => {
// 处理第一个异步操作的结果
return result1;
})
.then((result2) => {
// 处理第二个异步操作的结果
return result2;
})
.then((result3) => {
// 处理第三个异步操作的结果
return result3;
})
.catch((error) => {
// 处理操作失败的情况
});

TypeScript

官网: https://www.typescriptlang.org/

类型推断

1
let str = 'abc'

类型注解

1
2
let str: string;
str = 'abc';

指定输出参数类型

下面操作必须 自己知道 数组中 必然有元素 > 2的结果

否定 返回 undefined 会报错

1
2
3
let numArr = [1,2,5,4]
let res = numArr.find(item => item > 2) as number
console.log(res)

find 方法接受一个测试函数作为参数,这个测试函数对数组中的每个元素执行一次,直到找到一个使函数返回 true 的元素。在这个例子中,测试函数是 item => item > 2,意味着 find 方法会查找数组中第一个大于 2 的元素。

指定分配类型

1
2
3
4
5
6
7
8
9
let v1: string = 'abc'
let v2: number = 10
let v3: boolean = true
let nu: null = null
let un: undefined = undefined

// 分配多个类型
let v4: string | null = null
let v5: 1 | 2 | 3 = 2
1
2
let arr: number[] = [1 ,2 ,3]
let arr1: Array<String> = ['a', 'b', 'c']
1
2
3
let t1: [number, string, number] = [1, 'a', 2]
t1[0] = 1
// 指定位置必须为对应类型

增加?变为可选值

第三个值设为可选值之后,可以写,可以不写

1
let t1: [number, string, number?] = [1, 'a']

枚举类型

1
2
3
4
5
6
7
enum myEnum{
A,
B,
C
}
console.log(myEnum.A) // 0
console.log(myEnum[0]) // A

函数

1
2
3
function myFn(a: number, b: string): number{
return 100
}

? 设置节选

=是必选参数

必选放在最左边

可选放在右边

1
2
3
4
5
function myFn(a: number, b: string, c?: boolean, ...rest: number[]): number{
return 100
}

const f = myFn(20, 'abc', true, 1, 2, 3)

接口

interface

1
2
3
4
5
6
7
8
9
10
11
12
13
14
interface Obj {
name: string,
age: number
}

const obj: Obj = {
name: 'a',
age: 10
}

const obj2: Obj = {
name: 'b',
age: 11
}

type使用

1
2
3
type MyUserName = string | number
let a: MyUserName = 10
let b: MyUserName = "azz"

泛型

1
2
3
4
5
6
7
function myFn<T>(a: T, b: T): T[] {
return [a, b]
}

myFn<number>(1 ,2)
myFn<String>("a", "b")

map方法总结

map是javascript中的用法,用于创建一个新的数组

新数组的每个元素都是对原数组中的每个元素调用一个提供的函数的结果。

1
arry.map(callback(curValue, index, array), thisArg)

Callback: 回调函数

curValue: 数组中处理的元素

index(可选): 当前元素索引

array(可选):数组本身

thisArg(可选): 执行callback时调用this的值

Eg:

1
2
3
const nums = [1,2,3,4];
const nums2 = nums.map((num) => num * num)
console.log(nums2) // [1,4,9,16]

React中使用map渲染

从数组中生成一组元素(如 JSX 元素)。它通常用于将一个数据数组转换为 JSX 元素数组,从而动态生成 UI。

1
2
3
4
5
6
7
8
9
10
11
const todos = [
{id: 1, value: "learn notes1"},
{id: 2, value: "learn notes2"},
{id: 3, value: "learn notes3"}
];

<ul>
{todos.map((todo) => (
<li key={todo.id}>{todo.value}</li>
))}
</ul>

todos.map(...):对 todos 数组的每个元素调用提供的箭头函数。

箭头函数(todo) => (<li key={todo.id}>{todo.value}</li>)

参数 todo : todos 数组中的每一个对象。

返回值:对每个 todo 对象,返回一个 <li> JSX 元素,其中 key 属性是必需的,用于唯一标识每个列表项。

{todo.value}:用于显示当前待办事项的文本内容。

箭头函数

​ ES6的函数简洁式表达方法。

基本语法

1
2
3
const functionName = (para1, para2, ...) => {
reutrn output;
}

input: 入参数列表包裹在圆括号 () 中。如果没有参数,可以省略括号;如果只有一个参数,可以省略圆括号。

箭头 =>:用于分隔参数列表和函数体

函数体:

函数体包裹在花括号 {} 中。如果函数体只有一个简单的表达式,可以省略花括号和 return 关键字,返回值会被隐式返回。

Eg:

1
2
3
4
const sayHello => {
console.log("hello");
}
sayHello();
1
2
3
4
5
6
const square = (x) => {
return x * x;
}
// 或者
const square = x => x * x;
}
1
2
3
4
5
const add(a, b) => {
return a + b;
}

const add(a, b) => a + b;

常见用法

1
2
const nums = [1,2,3]
const nums2 = nums.map((num) => n * n);
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 Todo() {
const [todos, setTodos] = useState([]);
const [inputValue, setInputValue] = useState('');

function handleAdd() {
const newTodo = {
id: new Date().valueOf(),
value: inputValue,
completed: false
}

setTodos([...todos, newTodo]);
setInputValue('');
}


return (
<div>
<h1>Todo List</h1>
<button onClick={handleAdd}>Add Todo</button>
<ul>
{todos.map((todo)=> (<li key={todo.id}>{todo.value}</li>))}
</ul>
</div>
)
}

箭头函数还有filter, reduce

filter

filter 会遍历原始数组中的每个元素,并将满足条件的元素放入新的数组中。

语法

1
const newArray = array.filter(callback(element, index, array), thisArg)

callback:在数组每一项上调用的函数,该函数接收三个参数:

  • element:数组中正在处理的当前元素。
  • index(可选):当前元素的索引。
  • array(可选):filter 方法被调用的数组本身。

thisArg(可选):执行 callback 函数时用作 this 的值。

Eg:

1
2
const nums = [1,2,3,4,5];
const evens = nums.filter((num) => num%2 === 0);

过滤数组对象

1
2
3
4
5
6
const users = [
{name: 'b1', age: 12},
{name: 'b2', age 18},
]

const adults = users.filter((user) => user.age >= 18)
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
import React, { useState } from 'react';

function TodoApp() {
const [todos, setTodos] = useState([
{ id: 1, task: 'Learn React', completed: true },
{ id: 2, task: 'Write Code', completed: false },
{ id: 3, task: 'Read a book', completed: false },
{ id: 4, task: 'Exercise', completed: true },
]);

const [showCompleted, setShowCompleted] = useState(false);

// 过滤未完成的待办事项
const filteredTodos = todos.filter((todo) => !todo.completed);

return (
<div>
<h1>Todo List</h1>
<button onClick={() => setShowCompleted(!showCompleted)}>
{showCompleted ? 'Show All' : 'Show Incomplete'}
</button>
<ul>
{(showCompleted ? todos : filteredTodos).map((todo) => (
<li key={todo.id}>
{todo.task} {todo.completed ? '(Completed)' : ''}
</li>
))}
</ul>
</div>
);
}

export default TodoApp;
reduce

input组件

input涉及绑定其值到组件的状态,并在输入变化时更新状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function InputEx() {
const[inputValue, setInputValue] = useState();
const handleInput = (event) => {
setInputValue(event.target.value);
}
return(
<div>
<h2>Control Input Example</h2>
<input
type="text"
value={inputValue}
onChange={handleInput}
placeholder="Enter text here"
/>
</div>
)
}

How to Implement TodoList Project

https://codesandbox.io/p/sandbox/sad-james-5jsd6n?file=%2Fsrc%2FTodo.js%3A85%2C47

谁无暴风劲雨时,守得云开见月明。