caasih.net

ImageData

把一個 React Hook 搬到這裡,它叫 useImageData

R
G
B
import { useState, useEffect } from 'react'

export function useImageData(url) {
  const [imageData, setImageData] = useState()

  useEffect(() => {
    let img = new Image()
    img.crossOrigin = 'anonymous'
    img.src = url

    const f = () => {
      const canvas = document.createElement('canvas')
      canvas.width = img.width
      canvas.height = img.height
      const ctx = canvas.getContext('2d')
      ctx.drawImage(img, 0, 0)
      setImageData(ctx.getImageData(0, 0, img.width, img.height))
      img.removeEventListener('load', f)
    }

    img.addEventListener('load', f, false)

    return () => {
      img.removeEventListener('load', f)
      img = undefined
    }
  }, [url])

  return imageData
}

export default useImageData

也許有些人看了這些會覺得我不懂 React,在那邊嘴什麼奇怪的東西..。其實你們要說的那些我是知道的,而且大家介紹的也夠多了,我想從一個異於平常的角度,重新再來看待 React Hooks,希望給大家一個平常沒有想到的啟發。

把 React 的 render function 看成 reentrant function ,那就可以將 React Hooks 看成某種包含資料依賴關係的 trait/type class 。裡面放什麼則看你怎麼組合 useState, useEffectuseCallback 等 Hooks 。

不管它放的是什麼, CPS 變換會在 rerender 時完成,於是用的人拿到的是包裹的值,而不是時間上或空間上的容器。

CPS 變換這裡就不贅述,從 2011 開始寫 js 的大家肯定是知道的。

但我記得 ECMAScript 沒打算做 deep generator ,不知道未來 React Hooks 會怎麼走?像之前被 iCook 面試時,前端大大提到的那樣,靠 babel transpile 嗎?

後來找半天沒找到 ES Discuss 上關於 coroutine 的討論,但發現 the Little Calculist 2011 年曾寫過 Why coroutines won’t work on the web ,解釋為何 JS 不太可能有 coroutine 。


同理,善用 requestAnimationFrame 與 React Hook ,也可以拚出各種按時間變化的值。

☽︎
import React from 'react'
import { useRange } from '@caasi/hooks'
import styles from './index.css'

function Star({ x, y, children }) {
  return (
    <div className={styles.star} style={{ left: x, top: y }}>
      <div>{children}</div>
    </div>
  );
}

function useCirclePath({ x, y }, r, speed) {
  const rad = useRange(0, 2 * Math.PI / speed) * speed
  const dx = Math.cos(rad) * r
  const dy = Math.sin(rad) * r
  return { x: x + dx, y: y + dy }
}

function System() {
  const sun = { x: 200, y: 200 }
  const earth = useCirclePath(sun, 140, 1/1000)
  const moon = useCirclePath(earth, 20, -1/200)

  return (
    <div className={styles.system}>
      <Star {...sun}>☉</Star>
      <Star {...earth}>♁</Star>
      <Star {...moon}>☽︎</Star>
    </div>
  )
}

export default System

EDIT: 補上朋友建議的挑釁段落 XD

Creative Commons License