前一篇的 useToggle 顯然可以再更好,除了一般狀態之間切換,也可以再加入特定狀態的指定切換,來讓整體閱讀更直覺;也可以再嘗試額外加入 side-effect,來讓整體更多功能性。 (PLUS~ ULTRA~!)
我們需要:
繼承前一篇的內容,我們再加入 toggleOn
& toggleOff
:
function useToggle(defaultState = false) {
if(typeof defaultState !== 'boolean') {
throw new Error("useToggle: defaultState should be Boolean")
}
const [state, setState] = useState(defaultState)
const toggle = useCallback(() => setState((prev) => !prev),[])
const toggleOn = useCallback(() => setState(true),[])
const toggleOff = useCallback(() => setState(false),[])
return {isOn: state, toggle, toggleOn, toggleOff}
}
現在我們更可以透過這個 Hook 來掌控元件,想要開就 toggleOn,想要關就 toggleOff。
return 的部分則改使用 object,東西一多,用 array 的話反而太卡手。
這次搭配了不同畫面一起實作:
function Example() {
const [count, setCount] = useState(0)
const { isOn, toggle, toggleOn, toggleOff } = useToggle()
return (
<>
<Flex gap={2} sx={{ "& > *": { flex: 1 } }}>
<Button onClick={toggle}>TOGGLE</Button>
<Button onClick={toggleOn}>ON</Button>
<Button onClick={toggleOff}>OFF</Button>
</Flex>
<Fade in={isOn}>
<StyledBox>Hello (´・ω・`)</StyledBox>
</Fade>
</>
)
}
實作上的 component 都從 Chakra-UI 而來,客官們請多注意 hook 的表演
成果如下:
想開就開,想關就關 d(`・∀・)b
切換狀態之餘,我們可能會想伴隨一些其他動作,通常會另外這樣包裝:
function handleOn () {
toggleOn()
//do other stuff
}
可以進一步把這個想法加入到 useToggle 裡面,我們需要:
{ defaultState, onOn, onOff }
(分別為初始狀態、ture 時要觸發的 callback、以及 false 要觸發的 callback )toggleOn
/ toggleOff
會額外執行 onOn
/ onOff
(當有傳入的時候)toggle
改藉由當前的 state 來判斷要執行 toggleOn
or toggleOff
請原諒後來才發現取名 onOn,我承認很蠢
function useToggle(props = {}) {
const { defaultState, onOn, onOff } = props
if (defaultState !== undefined && typeof defaultState !== "boolean") {
throw new Error("UseToggle: defaultState should be Boolean")
}
const [state, setState] = useState(defaultState || false)
const toggleOn = useCallback(() => {
setState(true)
onOn?.()
}, [])
const toggleOff = useCallback(() => {
setState(false)
onOff?.()
}, [])
const toggle = useCallback(() => {
const action = state ? toggleOff : toggleOn
action()
}, [state])
return { isOn: state, toggle, toggleOn, toggleOff }
}
假設我們想統計這個元件有幾次被嘗試打開:
const { isOn, toggle, toggleOn, toggleOff } = useToggle({
onOn: () => setCount(count + 1),
})
這樣一來確實可以執行呢!
修但幾咧!怎麼好像怪怪的?
由於這邊使用了 useCallback,導致傳入的 onOn()
仍然是先前被記憶的 function,所以不管怎麼操作,執行上都會一直 0 + 1
,但聰明的大家應該想到:
「那就都把 useCallback 移除吧!」
「如果要用 useCallback ,就把會改變的東西放到 []
就好了啊」
「那就不要用這個方法唄~」
STOP!
既然是鐵人賽,讓我們再努力一下!
其實我們可以藉由 useRef + useEffect 來進一步實踐這個想法!
實際落成就留到明天再繼續吧!