先簡單說一下Hooks是什麼,在寫React組件時候,有兩種寫法,一種是類寫法,一種就是函數寫法,Hooks主要服務的對象仍是函數組件,由於函數組件相對類組件有些功能確實很差實現,好比生命週期鉤子,Hooks就是讓函數組件具備類組件能力的一個東西,Hooks的出現會給咱們帶來另一種組件實現思路,一直看到有些小夥伴們問Hooks會不會代替Redux,emmm...我以爲這應該不是一個概念吧,這些小夥伴沒必要擔憂。javascript
Tips:按照慣例聲明,筆者也是入門級選手,所寫文章深度不會達到大佬的文章水平,只但願能對像我同樣的入門級小夥伴有所幫助。java
先來看一個能夠管理狀態的組件在React中怎樣寫react
import React from 'react'
class Counter extends React.Component {
state = {
count: 0
}
componentDidMount() {
this.interval = setInterval(() => {
this.setState({
count: this.state.count + 1
})
}, 1000);
}
componentWillUnmount() {
if(this.interval) {
clearInterval(this.interval)
}
}
render() {
return (
<div>count is : {this.state.count}</div>
)
}
}
export default Counter;
複製代碼
以上代碼寫了一個簡單的計數器組件,管理了一個count狀態(就是一個名字叫count的數據),在組件加載完成後,執行定時器,將count狀態每秒+1,在組件要被卸載以前清除定時器(不清除會一直佔用內存,可能致使內存泄漏)。這裏添加定時器和卸載定時器都是經過生命週期鉤子來實現的,在Hooks引入以前,函數組件沒法使用生命週期函數的,因此沒法完成上述的狀態管理功能。編程
引入Hooks,讓函數組件也能夠完成狀態管理redux
先簡單使用兩個Hooks,下文還會詳細介紹數組
import React, {useState, useEffect} from 'react'
function CounterFunc() {
const [count, setCount] = useState(0)
useEffect(() => {
const interval = setInterval(() => {
setCount(c => c + 1)
},1000)
return () => clearInterval(interval)
},[])
return (
<div>count is : {count}</div>
)
}
export default CounterFunc;
複製代碼
這裏直接上了一段代碼,在最開頭引入了兩個函數:useState
和useEffect
。閉包
在函數組件CounterFunc中,經過useState(0)
來設置count的值,這裏useState(0)
會返回一個數組,數組第一個元素就是被賦值爲0的變量,第二個元素是能夠對第一個元素從新設置值得函數。咱們這裏經過數組解構的方式,將這兩個元素分別賦值給count
和setCount
,(若是不瞭解ES6的解構賦值,請先查閱阮一峯老師ES6書籍的相關部分)。函數式編程
咱們還用了useEffect()
函數,在函數裏定義了一個定時器,而後返回了一個函數,在返回的函數中清除了定時器,這個被返回的函數就至關於類組件中的componentWillUnmount()
生命周子函數了。而這個useEffect()
函數自己又至關於componentDidMount()
生命週期函數。函數
至此咱們也能很輕鬆理解useState
其實就至關於類組件中設置state的部分,它返回的數組第二個元素setCount()
是一個高階函數,咱們須要傳入一個c => c + 1
做爲參數,這個高階函數會將count
傳進c => c + 1
並將計算後的值從新賦值給count。 ui
對於狀態管理的Hooks,上面已經介紹了
useState()
,這裏會再加一個useReducer()
,useReducer
纔是基礎的狀態管理Hook
useState(0)
對useState傳遞的0只是對狀態設置了一個默認值,狀態改變後他就沒用了。
它返回的兩個元素我想你們應該也都清楚是什麼東西了,可是這裏要說的是第二個元素,它有兩種用法
setCount( 100 )
傳遞一個肯定的值setCount( c => c + 1)
傳遞一個函數,咱們上面使用的方式這裏說明一下咱們上面爲何不用setCount( count + 1 )
的方式,有興趣的小夥伴能夠試試,這樣咱們頁面的結果始終都是1,而不是預期的1,2,3...... 爲何會發生這種事?這是因爲閉包形成的,在state更新後,會從新執行咱們建立的函數組件,這時候const [count, setCount] = useState(0)
這段代碼會從新執行一遍,count每次都會被重置爲0,而後更新爲1。
上面說到了閉包,原本不想單獨說閉包,可是想了想,Hooks應該算是走函數式編程的道路吧,在學Hooks時候,咱們會遇到不少奇怪的現象,致使小夥伴感受很難,其實很大程度上跟沒掌握好閉包有很大關係。這裏就簡單說一下。
Tips: 請注意,若是你看別的文章從未搞懂過閉包,別擔憂,這裏我仍是有信心讓90%看我文章的人搞清楚什麼是閉包。有基礎的直接跳過!!!
要說閉包先說做用域
咱們這裏撇開let,const定義變量的方式,迴歸初心var 在JavaScript中,ES6出現以前是沒有塊級做用域的,可是它有個東西叫作函數做用域
var glob = '我是最外層定義的變量'
function func1() {
console.log(glob) // 這裏能夠引用上層的變量
var f1 = '我是func1中的變量'
function func1_1() {
var f1_1 = '我是函數func1_1中的變量'
console.log(glob)
console.log(f1) // 這裏能夠拿到上一層函數中定義的變量和最外層的變量
}
function func1_1() {
console.log(glob) // 這裏能夠拿到最外層的變量
console.log(f1_1) // 可是拿不到同一級別函數定義的變量
}
}
複製代碼
上面這代碼和註釋相信能讓你們看懂一點JavaScript中的做用域。一個函數,是不能拿到同級別函數裏面定義的變量,可是能拿到父級,爺爺級,爺爺爺級函數定義的變量。咱們能夠利用這裏特性對變量進行封裝。
function func1(param) {
var f1 = '只讓個人子孫拿到的變量‘
var f2 = param; // 這裏把param賦值給f2,它也只能被本身子孫拿到
function func1_1() {
console.log(f1, f2) //都能拿到
}
return func1_1
}
console.log(f1, f2) //兩個都拿不到,報錯
var res1 = func1('hello') // 你猜他的結果是什麼。
// 它的結果是一個函數,就是咱們返回的func1_1這個函數,猜錯的本身罰本身,給我點個贊,哈哈哈。
res1() // res1存放的就是返回的func1_1,因此再把它執行一遍
//打印出 `只讓個人子孫拿到的變量hello`
複製代碼
其實在咱們執行func1('hello')以後,func1的生命週期就結束了,原本,它裏面定義的f1,f2都應該在它生命週期結束後就再也訪問不到了,可是幸運的是,func1_1替他保存下了這兩個變量,使得func1尚未死透
這樣封裝變量就是閉包。
閉包插曲結束
咱們能夠經過setCount(c => c + 1)
傳入回調函數的方式避免閉包帶來的奇怪
現象。
function countReducer(state, action) {
switch(action.type) {
case 'add':
return state + 1;
case 'minus':
return state - 1;
default:
return state
}
}
......
// const [count, setCount] = useState(0)
const [count, dispatchCount] = useReducer(countReducer,0);
......
// setCount(c => c + 1)
dispatchCount({ type: 'add' })
......
複製代碼
首先咱們先在CounterFunc外面定義一個reducer,而後更改count的定義,以及count的更新,這裏useReducer的使用跟 redux中操做很像,後面會持續更新Redux的使用,請有須要的小夥伴關注一下,順手給個贊。
要注意的是,useReducer(countReducer,0)
的兩個參數,第一個是定義的countReducer第二個是默認值。咱們接收返回值的第二個元素固定寫爲dispach,或者這裏寫的dispachCount的格式。
這裏主要分享了5個知識點,一個是函數組件與類組件的區別,一個是useState, 再一個useEffect(後面會詳細說),而後介紹了閉包,最後說明了useReducer的使用,相信認真看到這裏的小夥伴對於React的Hooks已經有了個初步瞭解,而且對閉包不熟悉的小夥伴也已經對閉包有了深刻認識吧。