React基础知识扫盲
开始学习之前,首先给React知识扫扫盲
# React组件
定义组件最简单的方式就是编写JavaScript函数:
function Welcom(props) {
return <h1>Hello, {props.name}</h1>
}
2
3
该函数是一个有效的React
组件,因为它接受唯一带有数据的Props
对象并返回一个React
元素,这类组件被称为"函数组件",因为它本质上就是JavaScript
函数,后面会用到React Hook
,因此建议组件都这样创建。
注意
注意: 组件名称必须以大写字母开头。
React 会将以小写字母开头的组件视为原生 DOM 标签。例如,<div />
代表 HTML 的 div 标签,而 <Welcome />
则代表一个组件,并且需在作用域内使用 Welcome。
# 事件处理
React元素的事件处理和DOM元素很相似,但是语法上有一点不同:
- React事件的命名采用小驼峰式(camelCase),而不是纯小写。
- 使用JSX语法时你需要传入一个函数做为事件处理函数,而不是一个字符串。
<button onClick={e => console.log(e)}>
Activate Lasers
</button>
2
3
# 列表循环
可以通过使用{}在JSX内构件一个元素集合。
下面,我们使用JavaScript中的map()方法来遍历numbers数组。将数组中的每个元素变成li标签,最后我们将得到的数组赋值给listItems:
function List() {
const numbers = [1,2,3,4,5]
const listItems = numbers.map((number) =>
<li>{number}</li>
)
return <ul>{listItems}</ul>
}
2
3
4
5
6
7
# Hook
Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数。Hook 不能在 class 组件中使用 —— 这使得你不使用 class 也能使用 React。
这门课程会用到 State Hook, 和 Effect Hook。
# State Hook
这个例子用来显示一个计数器。当你点击但你,计数器的值就会增加:
import React, { useState } from 'react';
function Example() {
// 声明一个叫 “count” 的 state 变量。
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
在这里,useState 就是一个 Hook (等下我们会讲到这是什么意思)。通过在函数组件里调用它来给组件添加一些内部 state。React 会在重复渲染时保留这个 state。useState 会返回一对值:当前状态和一个让你更新它的函数,你可以在事件处理函数中或其他一些地方调用这个函数。
# Effect Hook
例如,下面这个组件在 React 更新 DOM 后会设置一个页面标题:
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
// 相当于 componentDidMount 和 componentDidUpdate:
useEffect(() => {
// 使用浏览器的 API 更新页面标题
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
当你调用 useEffect 时,就是在告诉 React 在完成对 DOM 的更改后运行你的“副作用”函数。由于副作用函数是在组件内声明的,所以它们可以访问到组件的 props 和 state。默认情况下,React 会在每次渲染后调用副作用函数 —— 包括第一次渲染的时候。
注意
# Hook使用规则
Hook 就是 JavaScript 函数,但是使用它们会有两个额外的规则:
- 只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用。
- 只能在 React 的函数组件中调用 Hook。不要在其他 JavaScript 函数中调用。(还有一个地方可以调用 Hook —— 就是自定义的 Hook 中)
# 状态提升
通常,多个组件需要反映相同的变化数据,这时我们建议将共享状态提升到最近的共同父组件中去。
import {useEffect, useState} from "react"
import { SearchPanel } from "./search-panel"
import { List } from "./list"
import { cleanObject, useMount, useDebounce } from "../../utils"
import * as qs from "qs"
const apiUrl = process.env.REACT_APP_API_URL
export const ProjectListScreen = () => {
const [param, setParam] = useState({
name: '',
personId: ''
})
const [users, setUsers] = useState([])
const [list, setList] = useState([])
const debouncedParam = useDebounce(param, 2000)
useEffect(() => {
fetch(`${apiUrl}/projects?${qs.stringify(cleanObject(debouncedParam))}`).then(async response => {
if(response.ok) {
setList(await response.json())
}
})
}, [debouncedParam])
useMount(() => {
fetch(`${apiUrl}/users`).then(async response => {
if(response.ok) {
setUsers(await response.json())
}
})
}, [])
return <div>
<SearchPanel users={users} param={param} setParam={setParam}/>
<List users={users} list={list}/>
</div>
}
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
这个组件中将user和list抽到父组件中,然后传给子组件。