内容目录
businessfragmentation
useEffect
是 React 中用于处理副作用
的钩子。并且useEffect
还在这里充当生命周期函数类似于Vue框架中的mounted,在之前你可能会在类组件中使用 componentDidMount
、componentDidUpdate
和 componentWillUnmount
来处理这些生命周期事件。
什么是副作用函数,什么是纯函数?
纯函数
- 输入决定输出:相同的输入永远会得到相同的输出。这意味着函数的行为是可预测的。
-
无副作用:纯函数
不会修改外部状态
,也不会依赖外部可变状态。因此,纯函数内部的操作不会影响外部的变量、文件、数据库等。
例子(纯函数)
const add = (x: number, y: number) => x + y
add(1,2) //3
副作用函数
- 副作用函数指的是那些在执行时会改变外部状态或依赖外部可变状态的函数。
- 可预测性降低但是副作用不一定是坏事有时候副作用带来的效果才是我们所期待的
- 高耦合度函数非常依赖外部的变量状态紧密
- 操作引用类型
-
操作本地存储例如
localStorage
-
调用外部API,例如
fetch
ajax
-
操作
DOM
useEffect用法
import {useEffect} from 'react'
useEffect(setup, dependencies?)
参数
- setup:Effect处理函数,可以返回一个清理函数。组件挂载时执行setup,依赖项更新时先执行cleanup再执行setup,组件卸载时执行cleanup。
- dependencies(可选):setup中使用到的响应式值列表(props、state等)。必须以数组形式编写如 dep1, dep2 。不传则每次重渲染都执行Effect。
返回值
useEffect 返回undefined
在React中useEffect专门用于处理副作用函数,副作用函数能做的事情useEffect
都能做,例如操作DOM
、网络请求、计时器等等
执行时机
组件挂载时执行
组件在挂载的时候将会执行useEffect
的副作用函数。
类似于
componentDidMount
组件更新时执行
- 无依赖项更新
useEffect
的副作用函数就会执行。
类似于
componentDidUpdate
+
componentDidMount
import { useEffect, useState } from "react"
const App = () => {
const [count, setCount] = useState(0)
const [name, setName] = useState('')
useEffect(() => {
console.log('执行了', count, name)
})
return (
<div id='data'>
<div>
<h3>count:{count}</h3>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
<div>
<h3>name:{name}</h3>
<input value={name} onChange={e => setName(e.target.value)} />
</div>
</div>
)
}
export default App
- 有依赖项更新
count
值发生改变时,
useEffect
的副作用函数就会执行。而当
name
值改变时,由于它不在依赖项数组中,所以不会触发副作用函数的执行。
import { useEffect, useState } from "react"
const App = () => {
const [count, setCount] = useState(0)
const [name, setName] = useState('')
useEffect(() => {
console.log('执行了', count, name)66
}, [count]) //当count发生改变时执行
return (
<div id='data'>
<div>
<h3>count:{count}</h3>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
<div>
<h3>name:{name}</h3>
<input value={name} onChange={e => setName(e.target.value)} />
</div>
</div>
)
}
export default App
- 依赖项空值
useEffect
的副作用函数只会执行一次,也就是组件挂载时执行。
适合做一些
初始化
的操作:获取某些需要直接展示的数据等等
import { useEffect, useState } from "react"
const App = () => {
const [count, setCount] = useState(0)
const [name, setName] = useState('')
useEffect(() => {
console.log('执行了', count, name)
}, []) //只会执行一次
return (
<div id='data'>
<div>
<h3>count:{count}</h3>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
<div>
<h3>name:{name}</h3>
<input value={name} onChange={e => setName(e.target.value)} />
</div>
</div>
)
}
export default App
组件卸载时执行
useEffect
的副作用函数可以返回一个清理函数,当组件卸载时,useEffect
的副作用函数就会执行清理函数。
useEffect
的副作用函数就会执行。
类似于
componentWillUnmount
import { useEffect, useState } from "react"
// 子组件
const Child = (props: { name: string }) => {
useEffect(() => {
console.log('render', props.name)
// 返回一个清理函数
return () => {
console.log('unmount', props.name)
}
}, [props.name])
return <div>Child:{props.name}</div>
}
const App = () => {
const [show, setShow] = useState(true)
const [name, setName] = useState('')
return (
<div id='data'>
<div>
<h3>父组件</h3>
<input value={name} onChange={e => setName(e.target.value)} />
<button onClick={() => setShow(!show)}>显示/隐藏</button>
</div>
<hr />
<h3>子组件</h3>
{show && <Child name={name} />}
</div>
)
}
export default App
清理函数应用场景
如我们下面这个例子,当name
值发生改变时,
useEffect
的副作用函数就会执行,并且会开启一个定时器,当
name
值再次发生改变时,
useEffect
的副作用函数就会执行清理函数,清除上一次的定时器。这样就避免了接口请求的重复执行。
import { useEffect, useState } from "react"
// 子组件
const Child = (props: { name: string }) => {
useEffect(() => {
let timer = setTimeout(() => {
fetch(`http://localhost:5174/?name=${props.name}`)
}, 1000)
return () => {
clearTimeout(timer)
}
}, [props.name])
return <div>Child</div>
}
const App = () => {
const [show, setShow] = useState(true)
const [name, setName] = useState('')
return (
<div id='data'>
<div>
<h3>父组件</h3>
<input value={name} onChange={e => setName(e.target.value)} />
<button onClick={() => setShow(!show)}>显示/隐藏</button>
</div>
<hr />
<h3>子组件</h3>
{show && <Child name={name} />}
</div>
)
}
export default App