let isInBatch = false
const effectQueue = []
function executeEffect() {
effectQueue.forEach(cb => {
cb()
})
}
/**
* 一个 createSignal方法,其接受一个初始值作为参数,
* 并返回-个数组,数组的第一个元素是一个函数,用于获取当前的值,
* 第二个元素是一个函数,用于更新当前的值
* @param {*} initialValue
* @example
* const [count,setCount]= createSignal(1);
* console.log('count:', count()) // 打印 1
* setCount(2)
* console.log('count:', count()) //打印 2
*/
function createSignal(initialValue) {
const target = { val: initialValue }
const getValue = () => {
return target.val
}
const setValue = (newValue) => {
target.val = newValue
if (!isInBatch) {
executeEffect()
}
}
return [getValue, setValue]
}
/**
* 接受一个函数作为参数,并并在函数执行时触发一次,
* 且每次 createSignal 返回的更新函数被调用时也会重新执行一次
* @param {*} callbackFn
* @example
* const [count, setCount] = createSignal(1)
* createEffect(()=>{console.log('count:', count()) // 打印 1
* setCount(2) // 触发打印 2
*/
function createEffect(callbackFn) {
// 这里完全可以提供一个 option,用于选择是否立即执行
callbackFn()
effectQueue.push(callbackFn)
}
/**
* 实现一个 batch 方法,在 batch 中执行多个 setter 操作,
* createEffect 的函数参数只被调用一次
*
* @param {*} callbackFn
* @example
* const [count, setCount] = createSignal(0)
* const [str, setStr] = createSignal('hello')
* createEffect(() => {
* console.log('count:', count(), 'str:', str())
* })
* batch(() => {
* setCount(1)
* setStr('hi')
* })
* // 输出
* // count: 0, str: hello
* // count: 1, str: hi
*/
function batch(callbackFn) {
isInBatch = true
callbackFn()
isInBatch = false
executeEffect()
}
const [count, setCount] = createSignal(0)
const [str, setStr] = createSignal('hello')
createEffect(() => {
console.log('count:', count(), 'str:', str())
})
setCount(3)
setCount(4)
batch(() => {
setCount(1)
setStr('hi')
})