/fre

:ghost: Tiny React-like framework with Time slicing and Algebraic effects.

Primary LanguageTypeScriptMIT LicenseMIT

fre logo

Fre

👻 Tiny React like framework with Concurrent.

Build Status Code Coverage npm-v npm-d brotli

Feature

  • 🎉 Functional Component and hooks API
  • 🎊 Time slicing and Algebraic effects
  • 🔭 keyed reconcilation algorithm

Real world

clicli.me

Any other demos click here

Use

yarn add fre
import { h, render, useState } from 'fre'

function App() {
  const [count, setCount] = useState(0)
  return (
    <div>
      <h1>{count}</h1>
      <button onClick={() => setCount(count + 1)}>+</button>
    </div>
  )
}

render(<App />, document.getElementById('root'))

Hooks API

useState

useState is a base API, It will receive initial state and return a Array

You can use it many times, new state is available when component is rerender

function App() {
  const [up, setUp] = useState(0)
  const [down, setDown] = useState(0)
  return (
    <div>
      <h1>{up}</h1>
      <button onClick={() => setUp(up + 1)}>+</button>
      <h1>{down}</h1>
      <button onClick={() => setDown(down - 1)}>-</button>
    </div>
  )
}

useReducer

useReducer and useState are almost the same,but useReducer needs a global reducer

function reducer(state, action) {
  switch (action.type) {
    case 'up':
      return { count: state.count + 1 }
    case 'down':
      return { count: state.count - 1 }
  }
}

function App() {
  const [state, dispatch] = useReducer(reducer, { count: 1 })
  return (
    <div>
      {state.count}
      <button onClick={() => dispatch({ type: 'up' })}>+</button>
      <button onClick={() => dispatch({ type: 'down' })}>+</button>
    </div>
  )
}

useEffect

It is the execution and cleanup of effects, which is represented by the second parameter

useEffect(f)       //  effect (and clean-up) every time
useEffect(f, [])   //  effect (and clean-up) only once in a component's life
useEffect(f, [x])  //  effect (and clean-up) when property x changes in a component's life
function App({ flag }) {
  const [count, setCount] = useState(0)
  useEffect(() => {
    document.title = 'count is ' + count
  }, [flag])
  return (
    <div>
      <h1>{count}</h1>
      <button onClick={() => setCount(count + 1)}>+</button>
    </div>
  )
}

If it return a function, the function can do cleanups:

useEffect(() => {
    document.title = 'count is ' + count
    reutn () => {
      store.unsubscribe()
    }
}, [])

useLayout

More like useEffect, but useEffect queue in requestAnimationFrame, but useLayout is sync and block commitWork.

useLayout(() => {
  document.title = 'count is ' + count
}, [flag])

useMemo

useMemo has the same parameters as useEffect, but useMemo will return a cached value.

function App() {
  const [count, setCount] = useState(0)
  const val = useMemo(() => {
    return new Date()
  }, [count])
  return (
    <div>
      <h1>
        {count} - {val}
      </h1>
      <button onClick={() => setCount(count + 1)}>+</button>
    </div>
  )
}

useCallback

useCallback is based useMemo, it will return a cached function.

const cb = useCallback(() => {
  console.log('cb was cached')
}, [])

useRef

useRef will return a function or an object.

function App() {
  useEffect(() => {
    console.log(t) // { current:<div>t</div> }
  })
  const t = useRef(null)
  return <div ref={t}>t</div>
}

If it use a function, It can return a cleanup and executes when removed.

function App() {
  const t = useRef(dom => {
    if (dom) {
      doSomething()
    } else {
      cleanUp()
    }
  })
  return flag && <span ref={t}>I will removed</span>
}

Fragments

Fragments will not create dom element.

<>someThing</>

The above code needs babel plugin @babel/plugin-transform-react-jsx

[
  "@babel/plugin-transform-react-jsx",
  {
    "pragma": "h",
    "pragmaFrag": "Fragment"
  }
]

time slicing

Time slicing is the scheduling of reconcilation, synchronous tasks, sacrifice CPU and reduce blocking time

resumable exception

resumable exception is a concept of algebraic effects. It can synchronously throw effects and then resume the execution of other logic of components.

key-based reconcilation

Fre implements a compact reconcilation algorithm support keyed, which also called diff.

It uses hash to mark locations to reduce much size.

License

_MIT @yisar