React基础知识扫盲

更新时间: 2022-02-14 15:06:41

开始学习之前,首先给React知识扫扫盲

# React组件

定义组件最简单的方式就是编写JavaScript函数:

function Welcom(props) {
  return <h1>Hello, {props.name}</h1>
}
1
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>
1
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>
}
1
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>
  );
}
1
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>
  );
}
1
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>
}
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

这个组件中将user和list抽到父组件中,然后传给子组件。