1.Hooks是什么?
- Hooks 是 **React v16.8** 中的新增功能
- 作用:为**函数组件**提供状态、生命周期等原本 class 组件中提供的 React 功能
- 注意:**Hooks 只能在函数组件中使用**,自此,函数组件成为 React 的新宠儿
有了 Hooks 以后,不能再把**函数组件**称为~~无状态组件~~了,因为 Hooks 为函数组件提供了状态
2.为什么要有Hooks
- 组件的状态逻辑复用问题
- class 组件自身的问题:(选择类组件还是函数组件;类组件中this指向问题;类组件不利于代码压缩和优化)
3.useState----基本使用
- `useState`使用场景:当你想要在**函数组件中,使用组件状态时**,就要使用 **useState**
- `useState`作用:为函数组件提供状态(state)
步骤:
- 导入 `useState` hook(import {useState} from 'react')
- 调用 `useState` 函数,并传入状态的初始值(useState(0) 0是默认值,可以写任意数据类型)
- 从 `useState` 函数的返回值中,拿到状态和修改状态的函数(函数返回一个数组,两个值(默认值,修改状态的函数))
- 在 JSX 中展示状态
- 在按钮的点击事件中调用修改状态的函数,来更新状态
代码小案例
import React,{useState} from 'react'
export default function useState用法() {
// 语法:useState(状态数据默认值)
const state=useState(0)
const state2=useState({name:'cc',age:18})
console.log(state);
console.log(state2);
// count表示默认值;setCount表示方法,用来修改值
const count=state[0]
const setCount=state[1]
return (
<div>
<ul>
<li>{count}</li>
<li onClick={()=>{setCount(count+1)}}>add</li>
<li></li>
</ul>
</div>
)
}
效果:点击add,count加1
4.useState----使用数组解构简化
代码小案例
import React,{useState} from 'react'
export default function useState用法() {
// 语法:useState(状态数据默认值)
// 1.简单类型
const [count,setCount]=useState(0)
const [isShow,setShow]=useState(true)
// 2.复杂类型
const [obj,setObj]=useState({name:'cc',age:18})
const [arr,setArr]=useState([1,2,3])
return (
<div>
<ul>
<li>{count}</li>
<li>
<button onClick={()=>{setCount(count+1)}}>add</button>
</li>
<li>
{isShow?'开':'关'}
</li>
<li>
<button onClick={()=>{setShow(!isShow)}}>开关</button>
</li>
<li>姓名:{obj.name},年龄:{obj.age}</li>
<li>
<button onClick={()=>{setObj({...obj,name:'小魔仙'})}}>变变变</button>
</li>
</ul>
<hr/>
{/* 数组 */}
<ul>
{
arr.map(item=>{
return <li key={item}>{item}</li>
})
}
<button onClick={()=>{setArr([...arr,Math.random()*1000])}}>数组添加</button>
</ul>
</div>
)
}
5.useState-------注意事项
- **React Hooks 只能直接出现在 函数组件 中*
- **React Hooks不能嵌套在 if/for/其他函数 中
6.useEffect---------基本使用
- 目标:**能够在函数组件中操作DOM(处理副作用)
- 使用场景:当你想要在函数组件中,处理副作用(side effect)时就要使用 useEffect Hook
- 作用:处理函数组件中的一些副作用(side effect)
- 注意:在实际开发中,副作用是不可避免的。因此,react 专门提供了 **useEffect** Hook **来处理函数组件中的副作用
语法:
- 参数:回调函数(称为 **effect**),就是**在该函数中写副作用代码
- 执行时机:该 effect 会在组件第一次渲染以及每次组件更新后执行
- 相当于 componentDidMount + componentDidUpdate
import { useEffect } from 'react'
useEffect(function effect() {
document.title = `当前已点击 ${count} 次`
})
useEffect(() => {
document.title = `当前已点击 ${count} 次`
})
页面标题更改,小案例
import React, { useState,useEffect } from 'react'
export default function useEffect用法() {
const [count,setCount]=useState(10000)
// 需求:每次count变化,html页面的title随着变化
// 语法:useEffect(callback函数)
// 执行:相当于componentDidMount+componentDidUpdate(2合1)
// 1.组件第一次渲染,会执行一次callback函数
// 2.状态数据变化,callback函数会再次执行
useEffect(()=>{
console.log('useEffect');
// 操作DOM(副作用)
document.title=`ha ${count}`
}
)
return (
<div>
<ul>
<li>{count}</li>
<li>
<button onClick={()=>setCount(count+10000)}>add</button>
</li>
</ul>
</div>
)
}
7.useEffect-------依赖
- 目标:**能够设置 useEffect 的依赖只在 count 变化时执行相应的 effect
- 问题:如果组件中有另外一个状态,另一个状态更新时,刚刚的 effect 回调也会执行
- 默认情况:只要状态发生更新 useEffect 的 effect 回调就会执行
- 性能优化:**跳过不必要的执行,只在 count 变化时,才执行相应的 effect
- 语法:(1.第二个参数:可选,也可以传一个数组,数组中的元素可以成为依赖项(deps);2.该示例中表示:只有当 count 改变时,才会重新执行该 effect)
案例
import React, { useState,useEffect } from 'react'
export default function useEffect用法() {
const [count,setCount]=useState(10000)
const [num,setNum]=useState(0)
// 需求:每次count变化,html页面的title随着变化
// 语法:useEffect(callback函数,[依赖1,依赖2,...])
// 执行:相当于componentDidMount+componentDidUpdate(2合1)
useEffect(()=>{
console.log('useEffect');
// 操作DOM(副作用)
document.title=`ha ${count}`
},[count]
)
return (
<div>
<ul>
<li>{count}</li>
<li>{num}</li>
<li>
<button onClick={()=>setCount(count+10000)}>add-count</button>
</li>
<li>
<button onClick={()=>setNum(num+1)}>add-num</button>
</li>
</ul>
</div>
)
}
8.useEffect----------不要对依赖项撒谎
- useEffect 回调函数(effect)中用到的数据(比如,count)就是依赖数据,就应该出现在依赖项数组中
- 如果 useEffect 回调函数中用到了某个数据,但是,没有出现在依赖项数组中,就会导致一些 Bug 出现!
const App = () => {
const [count, setCount] = useState(0)
// 错误演示:
useEffect(() => {
document.title = '点击了' + count + '次'
}, [])
return (
<div>
<h1>计数器:{count}</h1>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
)
}
9.useEffect----------依赖是一个空数组
- 目标:**能够设置useEffect的依赖,让组件只有在第一次渲染后会执行
- useEffect 的第二个参数,还可以是一个空数组([]),表示只在组件第一次渲染后执行 effect
- 使用场景:1 事件绑定 2 发送请求获取数据 等
小案例
import axios from 'axios'
import React,{useEffect, useState} from 'react'
export default function useEffect空数组() {
const [list,setList]=useState([])
var getList=async()=>{
var {data}=await axios.get('http://localhost:8888/list')
console.log(data);
setList(data)
}
useEffect(()=>{
console.log('useEffect');
getList()
},[])
return (
<div>
<ul>
{list.map(item=>{
return <li key={item.id}>{item.id}</li>
})}
</ul>
</div>
)
}
10.useEffect------清理工作
相当于:componentWillUnmount
- 目标:**能够在组件卸载的时候清除注册的事件
- effect 的**返回值**是可选的,可省略。也可以返回一个**清理函数**,用来执行事件解绑等清理操作
- 清理函数的执行时机:(1.**清理函数**会在组件卸载时以及下一次副作用回调函数调用的时候执行,用于清除上一次的副作用。2.如果依赖项为空数组,那么会在组件卸载时会执行。相当于组件的`componetWillUnmount)
useEffect(() => { // 这个返回的函数,会在该组件卸载时来执行 // 因此,可以去执行一些清理操作,比如,解绑 window 的事件、清理定时器 等 return () => window.removeEventListener('resize', handleResize) }, [])
条件:依赖项为空,useEffect中return函数
11.useEffect---------语法总结
// 1
// 触发时机:1 第一次渲染会执行 2 每次组件重新渲染都会再次执行
// componentDidMount + ComponentDidUpdate
useEffect(() => {})
// 2(使用频率最高)
// 触发时机:只在组件第一次渲染时执行
// componentDidMount
useEffect(() => {}, [])
// 3(使用频率最高)
// 触发时机:1 第一次渲染会执行 2 当 count 变化时会再次执行
// componentDidMount + componentDidUpdate(判断 count 有没有改变)
useEffect(() => {}, [count])
// 4
useEffect(() => {
// 返回值函数的执行时机:组件卸载时
// 在返回的函数中,清理工作
return () => {
// 相当于 componentWillUnmount
}
}, [])
useEffect(() => {
// 返回值函数的执行时机:1 组件卸载时 2 count 变化时
// 在返回的函数中,清理工作
return () => {}
}, [count])
12.useEffect-----发送请求
- 目的:**能够在函数组件中通过useEffect发送ajax请求
- 在组件中,可以使用 useEffect Hook 来发送请求(side effect)获取数据
- 注意:**effect 只能是一个同步函数,不能使用 async(因为如果 effect 是 async 的,此时返回值是 Promise 对象。这样的话,就无法保证清理函数被立即调用)
- 为了使用 async/await 语法,可以在 effect 内部创建 async 函数,并调用
// 错误演示:不要给 effect 添加 async
useEffect(async () => {
const res = await axios.get('http://xxx')
return () => {}
}, [])
// 正确使用
useEffect(() => {
const loadData = async () => {
const res = await axios.get('http://xxx')
}
loadData()
return () => {}
}, [])