一. 废话不多说上才艺
import React, { useState } from 'react'
export default function Test() {
const [title, setTitle] = useState<string>('我是title')
return (
<div onClick={() => setTitle('更改了')}>
{ title }
</div>
)
}
🥜: 上面一小段代码只是最简单的使用了useState,实现了初始化,赋值,渲染等一系列操作,它干了什么事 ?
- 传入初始值并定义类型,类型: <string> 初始值: ‘我是title’
- 返回一个数组,第一项是返回的变量存储的就是对应的值, 第二项是更改该值的函数
- 当调用第二项时,会更改当前变量,并且触发当前页面重新渲染
结论: 既然我们知道它的运作方式,那么我们就可以模拟一个属于自己的useState,并理解它。
二. myUseState (单人版)
import React, { useEffect } from 'react'
import ReactDOM from 'react-dom'
const root = document.getElementById('root')
//顶层存储数据
let _value: any
const myUseState = <T, >(initialValue: T) => {
// 初始value
_value = _value === undefined ? initialValue : _value
const setValue = (v: T) => {
_value = v
render()
}
return [ _value, setValue ]
}
//模拟的render函数
const render = () => ReactDOM.render(<Index />, root);
export default function Index() {
const [a, setA] = myUseState<string>('1')
const handleClick = () => {
setA(a + 1)
}
useEffect(() => {
console.log('值为', a)
console.log(setA)
}, [])
return (
<div>
<div>{ a }</div>
<div onClick={handleClick}>点击我</div>
</div>
)
}
🥜: 如何实现自己的useState
- 声明一个全局的变量value,用来存储初始值以及后续的更新值
- 声明useState函数,接受泛型T类型,以及初始值initialValue
- 将初始值赋值给全局变量value,当value为未定义时就将初始值赋给全局变量否则为它本身
- 声明返回值的第二项set函数用来更新最新的值
- 返回一个数组 [] 第一项为最新值,第二项为更新函数
- 当调用更新函数时,会触发重新渲染对应的组件页面,从而实现整个流程
- 单人版 --- 多此调用无法使用
原理: 闭包,闭包是hooks的关键
三. myUseState (多人版,进阶版)
import React, { useEffect } from 'react'
import ReactDOM from 'react-dom'
const root = document.getElementById('root')
//顶层存储数据
let _values: any[] = []
let index: number = 0
const myUseState = <T, >(initialValue: T) => {
console.log(index)
// 初始value
let currentIndex = index
_values[currentIndex] = _values[currentIndex] === undefined ? initialValue : _values[currentIndex]
const setValue = (v: T) => {
// 闭包本包
_values[currentIndex] = v
index = 0
render()
}
index += 1
return [ _values[currentIndex], setValue ]
}
//模拟的render函数
const render = () => ReactDOM.render(<Index />, root);
export default function Index() {
const [a, setA] = myUseState<string>('1')
const [b, setB] = myUseState<string>('2')
const handleClickA = () => {
setA(a + 1)
}
const handleClickB = () => {
setB(b + 2)
}
useEffect(() => {
console.log('值为', a)
console.log(setA)
console.log(_values)
}, [])
return (
<div>
<div>{ a }</div>
<div>{ b }</div>
<div onClick={handleClickA}>点击我</div>
<div onClick={handleClickB}>点击我</div>
</div>
)
}
🥜:与单人版基本一致
- 不同: 存储值的为一个集合,每次变更与返回都是根据全局index与currentIndex实现的
- 关键: currentIndex 值,利用闭包,函数嵌套函数内部函数持续引用外部函数变量currentIndex,导致每次初始化使用useState都会记住当时的下标,currentIndex,当调用对应的set函数时,会在底层找到闭包中对应的下标进行修改。