無測無用
useLess
當應用程式狀態更新時, useState
hook 讓我們無視時間,拿到最新的值,好像我們一開始看到的就是最後的值一樣。
換個角度看,也可以說 useState
幫我們把值攤到時間上了。例如可以寫一個 useArray
,把陣列中的值變成一系列更新:
import { useState, useEffect } from 'react';
export default function useArray(xs) {
const [index, setIndex] = useState(0);
useEffect(() => {
setIndex(0);
}, [xs]);
useEffect(() => {
if (index < xs.length - 1) setIndex(index + 1);
}, [xs, index]);
return xs[index];
}
let xs =
這東西很沒用,當你把 xs = [a, b, c]
丟給它,只會看到最後的 。
useSpace
但既然能把值攤到時間上,能不能反過來把時間上的變化,蒐集起來呢?
可以設計一個 useSpace
hook :
import { useState, useEffect } from 'react';
import useFold from './use-fold';
const concat = (acc = [], x) => [...acc, x];
function useSpace(state) {
return useFold(state, concat, []);
}
export default useSpace;
於是我們又把 變回了
[]
。
useWebSocket
靠 React Hooks 與 event listener 互動時,會遇上:「更新值的 function 得隨著值一起更新,於是得一直 add event listener ,再 remove event listener 」。
有了 useSpace
,我們可以:
function useWebSocket(url) {
// ...
const [message, setMessage] = useState();
const messages = useSpace(message);
// ...
const handleMessage = useCallback(({ data }) => {
setMessage(data);
}, [setMessage]);
// ...
}
於是 handleMessage
不用看到整個 messages
。
但這個問題完全可以靠傳遞一個 update function 給 setState
解決,無用。
<SpaceTime />
我們還可以做出這樣的 component :
import { useSpace } from '@caasi/hooks'
function SpaceTime({ children }) {
return useSpace(children)
}
export default SpaceTime;
<SpaceTime />
展開過去繪製過的 children ,於是這樣寫:
import React from 'react'
import styles from './index.css'
function ColorRect({ data }) {
return (
<div
className={styles.colorRect}
style={data}
/>
)
}
export default ColorRect
<SpaceTime>
<ColorRect data={{ backgroundColor: color }} />
</SpaceTime>
就能達成下面的效果:
點下面的方塊:
但這也可以靠 useState
做到,無用。😂
map
既然我們可以把值攤到時間上再組合回來,就可以把 Array::map
藏起來:
import React, { Children, cloneElement } from 'react'
import { useArray } from '@caasi/hooks';
import SpaceTime from './SpaceTime'
function List({ data, children }) {
const x = useArray(data)
return x === undefined
? null
: (
<div>
<SpaceTime>
{cloneElement(Children.only(children), { data: x })}
</SpaceTime>
</div>
)
}
export default List
再一口氣畫完一張圖:
<List data={styleMap}>
<List>
<ColorRect />
</List>
</List>
超無用!❤️
更多無用
- 因為新版的
useSpace
沒辦法 reset ,所以偷偷使用undefined
當成分隔符號。 - 要是連續兩個值完全一樣,會被
useArray
忽略。 - 這些 custom hooks 很難測試,只好靠 E2E test 工具
cypress
來測。
感謝朋友在閒聊時,提供標題 XD