昨天我们介绍完 React 最常用的 useState hook,今天就来聊聊在第二常用的 useEffect hook 吧!
根据官网的说明,useEffect 在 function component 是扮演着处理 side effect 的角色。
看完上面简短的说明,相信应该会有一个疑问是说,什麽是 side effect?首先要了解 side effect 我们先来简单了解一下什麽是 pure function。
Pure function 指的是当相同的输入,永远会得到相同的输出,而且没有任何显着的副作用。例如:
function double(x){
return 2 * x
}
double(2) // 4
double(2) // 4
double(2) // 4
在上面 double 函式中,我们很单纯的只做运算,而且输入相同的值 2,都只会输出 4。
那到底怎麽样算是一个副作用呢?例如:
let doNotChange = 10
function double(x){
console.log('hello') // 副作用
doNotChange += 5 // 副作用
return 2 * x
}
double(2) // 4
double(2) // 4
double(2) // 4
以上面的例子来看,我们呼叫 console.log() 更动浏览器的主控台的输出,或是更动到外部的变数,像这样有更动到外部环境都具有副作用。
副作用并不代表一定是不好的,而是它有可能会影响到其他环境的使用情况。
初步了解什麽是 pure function 及 side effect 之後,我们可以试想把 function component 作为一个 pure function 来看待。当我们传入的 props 都是固定的,那回传的 UI 就会是一样的。而其他的,例如: 串接第三方 api 或是呼叫浏览器的 api 等等,都会被归类为 side effect。
而 useEffect 这个 hook 就是设计来处理并执行这些 side effect 的。
以下是 useEffect 的使用方式。
useEffect(()=>{
// 每一次 render 後会执行
})
useEffect(()=>{
// 只有在第一次 render 後执行
}, [])
useEffect(()=>{
// 第一次 render 後会执行以外,每当 count 变数的值有变动时执行
}, [count])
useEffect(()=>{
// 第一次 render 後执行以外,每当 count 变数的值有变动时执行,但会先等 return 的函式执行完後才会执行这里
return ()=>{
// 第一次 render 不执行,第二次重新 render 後先执行这个函式
}
}, [count])
useEffect 这个函式接收两个参数,第一个参数是函式,要执行的 side effect 会放在这个函式中执行;第二参数则是一个阵列,被称为 dependency array,因为 useEffect 会根据阵列中的值变化而决定第二次 render 後要不要执行第一个被当作参数传进去的函式,如果是空阵列,那 useEffect 只会在第一次 render 过後执行。
让我们在前几天的 useState 的范例加上 useEffect,来观察一下上面这四种使用方式:
const Counter = () => {
const [count, setCount] = React.useState(0)
//使用 useState 建立 Count 状态,并将 0 设为初始状态
React.useEffect(()=>{
// 每一次 render 後会执行
console.log('No.1')
})
React.useEffect(()=>{
// 只有在第一次 render 後执行
console.log('No.2')
}, [])
React.useEffect(()=>{
// 第一次 render 後会执行以外,每当 count 变数的值有变动时执行
console.log('No.3')
}, [count])
React.useEffect(()=>{
// 第一次 render 後执行以外,每当 count 变数的值有变动时执行,但会先等 return 的函式执行完後才会执行这里
console.log('No.4')
return ()=>{
// 第一次 render 不执行,第二次重新 render 後先执行这个函式
console.log('No.5')
}
}, [count])
console.log('No.6 render component') // render
const increaseHandler = () => {
setCount(prev => prev + 1)
// 点击 plus 按钮,将 count 加 1 ,并使用 setCount 改变 Count 状态
}
const decreaseHandler = () => {
if (count === 0) return
setCount(prev => prev - 1)
// 点击 minus 按钮,将 count 减 1 ,并使用 setCount 改变 Count 状态
}
return (
<div>
<button onClick={decreaseHandler}></button>
<span>{count}</span>
<button onClick={increaseHandler}></button>
</div>
)
};
ReactDOM.render(<Counter />, document.getElementById('root'));
大家可以猜猜看上面六个 console.log ,在第一次 render component 後,印出的顺序会是什麽? 接着当 count 值改变,触发 re-render 後,印出的顺序又会是如何?
第一次 render 的解答:
"No.6 render component"
"No.1" // 每一次 render 後会执行
"No.2" // 只有在第一次 render 後执行
"No.3" // 第一次 render 後会执行以外,每当 count 变数的值有变动时执行
"No.4" // 第一次 render 後执行以外,每当 count 变数的值有变动时执行,但会先等 return 的函式执行完後才会执行这里
第二次 render 的解答:
"No.6 render component"
"No.5" // 重新 render 後先执行这个函式
"No.1" // 每一次 render 後会执行
"No.3" // 第一次 render 後会执行以外,每当 count 变数的值有变动时执行
"No.4" // 第一次 render 後执行以外,每当 count 变数的值有变动时执行,但会先等 return 的函式执行完後才会执行这里
不知道大家有没有猜对呢?
以上就是 useEffect 基本的介绍,有什麽问题都欢迎在下方留言。
该文章同步发布於:我的部落格
<<: 找LeetCode上简单的题目来撑过30天啦(DAY12)
大家好我是 Gui,一名刚於私立科大资管系毕业的社会新鲜人,这是我第一次参与 IT 铁人赛,既紧张又...
在有必要的时候,我们可能需要使用寄信来通知使用者、寄信给公会小姐、 把AI数据视觉化的资料寄给老板。...
Epplus於linux环境下无预设lib的报错与解决 Epplus为.NET众所皆知的Excel读...
Hi Dai Gei Ho~ 我是Winnie ~ 不知道大家记不记得,在昨天文章中我们提到了 如果...
今天要来学习程序语言中非常重要的一个概念(功能)-回圈,回圈到底可以拿来干嘛呢?先来看个例子: 如果...