首先,这不是React useState的源码,只是一种实现方法。
useState基本用法就是:传入一个初始值,然后返回该值和修改该值的方法,达到在函数组件修改值并触发视图更新的效果。
const [state,setState] = useState(0)
可以看出,hooks useState 函数通过数组的形式返回了两个值,类似下面这样的代码,通过解构的方式导出为不同的名称。
function useState (initialState) {
return [_state,_setState]
}
函数中应该保存一份初不同和一个改变该值的方法,需要注意,因为每次setState都会执行render(),导致_state每次都是初始值。所以需要判断是否已经存在_state,不存在则赋予初始值,否则取上次的值。
let _state
function useState (initialState) {
_state = _state === undefined ? initialState :_state
const _setState = (newValue) => {
_state = newValue
render()
}
return [_state,_setState]
}
function render () {
ReactDOM.render (
<App />
document.querySelect('#app')
)
}
return {useState}
每次设置新值时,手动调用render方法,可以看到值在发生变化,当然在React源码中做了很多处理,不会这么简单。
const {useState} = MyState
function App (){
const [count ,setCount] = useState(0)
return (
<div>
<h2>{count}</h2>
<button onClick={()=>setCount(count+1)}>+1</button>
</div>
)
}
不过有一种情况,当setState时传入一个回调函数,需要执行该回调函数,可以写出下面的的代码
const _setState = (params) => {
if(typeof params === 'function'){
_state = params(_state)
}else{
_state = params
}
render()
}
以上写法只适用单个useState的情况,不过在业务中极少只写一个setState,更多是以下的情形
const [name,setName] = useState('ahjet')
const [guitar,setGuitar] = useState('ibanez')
这种情况就需要保存多个值的标识,通过标识取值个设置新值,方法是通过有序列表数组的方法保存各个state和setState函数,当设置新值时,就去执行对应下标下的函数。
const AhjetState = (()=>{
let states = [] //保存值的数组
let stateSetters = [] //保存设置新值函数的数组
let stateIndex = 0 // 下标
})
首先是取值的方法,判断值数组中对应下标是否已存在值,是则取该值,否则赋予新值。
function createState(initialState,stateIndex){
return states[stateIndex] !== undefined ? states[stateIndex] :initialState
}
然后是设置新值的方法,也是通过判断是否是一个函数,是则执行该函数。通过返回一个设置新值的函数,保存在函数数组中。
function createStateSetter (stateIndex){
return function(newState){
if(typeof newState === 'function'){
states[stateIndex] = newState(states[stateIndex])
}else{
states[stateIndex] = newState
}
render()
}
}
最后就是useState主方法。每次调用useState时,通过闭包的方式保存了stateIndex的值,每次stateIndex会增加1,如果函数数组中没有更新值的方法,则会保存该方法,然后通过下标取出对应的值和对应的更新方法。
function useState(initialState){
states[stateIndex] = createState(initialState,stateIndex)
if(!stateSetters[stateIndex]){ stateSetters.push(createStateSetter(stateIndex))
}
const _state = states[stateIndex],
_setState = stateSetters[stateIndex];
stateIndex ++
return [_state,_setState]
}
完