为什么要有Hook

本质:让函数组件可以拥有状态

useState

基础使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 1.导入useState函数
import { useState } from 'react'

function App () {
// 2.调用useState,设置初始值(此处是初始值0)
// 3.从useState返回值中拿到状态和修改状态的方法
// 返回值为一个数组,包含状态和状态修改方法
const [count, setCount] = useState(0)
return (
// 4.使用状态和状态修改方法
<button
onClick={() => { setCount(count + 1) }}
>{count}</button>
)
}

export default App
  1. 在修改状态时,一定要用新值代替旧值而不是直接修改,尤其是引用类型
  2. useState函数多次执行相互独立,每次调用为函数组件提供一个状态
  3. useState不能嵌套在for/if/其他函数中,因为react按照hook调用顺序识别每个hook

回调函数作为状态参数

回调函数return出去的值将作为初始值,只在渲染组件时执行该回调函数

这样可以根据传参提供不同的初始值

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

function Counter (props) {
const [count, setCount] = useState(() => {
return props.count
})
return (
<button
onClick={() => { setCount(count + 1) }}
>{count}</button>
)
}

function App () {
return (
<>
<Counter count={10} />
<Counter count={20} />
</>
)
}

export default App

useEffect

为react函数提供副作用处理 (主作用指根据数据渲染UI,其余都属于副作用,常见副作用有手动修改dom,数据请求,localstorage修改等)

基础使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 引入useEffect
import { useEffect, useState } from 'react'

function App () {
const [count, setCount] = useState(0)
useEffect(() => {
// dom修改操作
document.title = `当前点击了${count}次`
})
return (
<button
onClick={() => { setCount(count + 1) }}
>{count}</button>
)
}

export default App

useEffect依赖项

基础使用中是不添加依赖项的情况,在组件初始渲染和任何状态改变导致的组件更新时都会执行

当我们添加空数组的时候,表示只在初始渲染的时候执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { useEffect, useState } from 'react'

function App () {
const [count, setCount] = useState(0)
useEffect(() => {
document.title = `当前点击了${count}次`
}, [])
return (
<button
onClick={() => { setCount(count + 1) }}
>{count}</button>
)
}

export default App

当我们在数组中添加依赖项时,只有依赖项改变才会执行useEffect

1
2
3
useEffect(() => {
document.title = `当前点击了${count}次`
}, [count])

useEffect清理副作用

有时候useEffect中的副作用操作是需要被清理的,比如计时器操作,如下代码所示,如果没有副作用清理操作,当组件被删除的时候计时器仍在运行,可以在console中看到

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

function Test () {
useEffect(() => {
setInterval(() => {
console.log('计时器运行中')
}, 1000)
})
return <div>Test</div>
}

function App () {
const [flag, setFlag] = useState(true)
return (
<>
<button onClick={() => setFlag(false)}>delete</button>
{flag ? <Test /> : null}
</>
)
}

export default App

useEffect清理副作用的操作流程一般如下所示

1
2
3
4
5
6
7
8
9
10
useEffect(() => {               
/*
此处为副作用操作
*/
return () => {
/*
在这里写清理副作用的代码
*/
}
})

对于之前的计时器代码的清理副作用操作如下所示

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
import { useEffect, useState } from 'react'

function Test () {
useEffect(() => {
const timeId = setInterval(() => {
console.log('计时器运行中')
}, 1000)
return () => {
clearInterval(timeId)
}
})
return <div>Test</div>
}

function App () {
const [flag, setFlag] = useState(true)
return (
<>
<button onClick={() => setFlag(false)}>delete</button>
{flag ? <Test /> : null}
</>
)
}

export default App

useRef

用于获取绑定dom对象或是组件对象

获取dom

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 1.导入useRef
import { useEffect, useRef } from 'react'

function App () {
// 2.使用useRef传入null,返回值是一个对象,current属性存放拿到的dom对象
const testRef = useRef(null)
useEffect(() => {
console.log(testRef)
}, [testRef])
return (
{/* 3.用ref来绑定dom*/}
<>
<h1 ref={testRef}>hello world</h1>
</>
)
}

export default App

获取组件

1
2
3
4
5
6
7
8
// Foo.js
class Foo extends React.Component {
render(){
return <div>Foo</div>
}
}

export default Foo
1
2
3
4
5
6
7
8
9
10
11
12
13
// App.js
import { useEffect, useRef } from 'react'
import Foo from './Foo'
function App() {
const h1Foo = useRef(null)
useEffect(() => {
console.log(h1Foo)
}, [])
return (
<div> <Foo ref={ h1Foo } /></div>
)
}
export default App

useContext

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
// 1.导入context
import { createContext, useContext } from 'react'
// 2.创建context对象
const Context = createContext()

function Foo () {
return <div>Foo <Bar /></div>
}

function Bar () {
// 4.底层组件通过useContext取出内容
const { name, list } = useContext(Context)
return <div>Bar {name} {list}</div>
}

const name = 'this is name'
const list = [1, 2, 3]

const value = {
name,
list
}

// 3.顶层组件用Provider包裹根元素
function App () {
return (
<Context.Provider value={value}>
<div><Foo /></div>
</Context.Provider>
)
}

export default App