caasih.net

無測無用

useLess

當應用程式狀態更新時, useState hook 讓我們無視時間,拿到最新的值,好像我們一開始看到的就是最後的值一樣。

換個角度看,也可以說 useState 幫我們把值攤到時間上了。例如可以寫一個 useTimeArray ,把陣列中的值變成一系列更新:

import { useState, useEffect } from 'react'

function useTimeArray(as) {
  const [s, set] = useState()

  useEffect(() => {
    set()
    if (!Array.isArray(as)) return
    as.map(v => setImmediate(set, v))
  }, [as])

  return s
}

export default useTimeArray

let xs =  

這東西很沒用,當你把 xs = [a, b, c] 丟給它,只會看到最後的

useSpace

但既然能把值攤到時間上,能不能反過來把時間上的變化,蒐集起來呢?

可以設計一個 useSpace hook :

import { useState, useEffect } from 'react';

function useSpace(state) {
  const [states, setStates] = useState();

  useEffect(() => {
    if (state === undefined) {
      setStates();
      return;
    }

    setStates((ss = []) => [...ss, state]);
  }, [state]);

  return [states, setStates];
}

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, setMessages] = useSpace(message);

  // ...

  const handleMessage = useCallback(({ data }) => {
    setMessage(data);
  }, [setMessage]);

  // ...
}

於是 handleMessage 不用看到整個 messages

ws://echo.websocket.org 通訊看看:

但這個問題完全可以靠傳遞一個 update function 給 setState 解決,無用。

<SpaceTime />

我們還可以做出這樣的 component :

import { useSpace } from '@caasi/hooks'

function SpaceTime({ children }) {
  const [cs] = useSpace(children)
  return cs === undefined ? null : cs
}

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 useTimeArray from './use-time-array'
import SpaceTime from './SpaceTime'

function List({ data, children }) {
  const x = useTimeArray(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>

超無用!❤️

更多無用

  • 這幾個 hooks 把 undefined 當成 reset 用的特殊值。
  • 要是連續兩個值完全一樣,會被 useTimeArray 忽略。
  • 目前 react-hooks-testing-library 無法測試 useSpace

感謝朋友在閒聊時,提供標題 XD

Creative Commons License