👻 Tiny Coroutine framework with Fiber.
-
Coroutine with Fiber — This is an amazing idea, which implements the coroutine scheduler in JavaScript, and the rendering is asynchronous, which supports Time slicing and suspense components.
-
Highly-optimized algorithm — Fre has a better reconciliation algorithm, which traverses from both ends with O (n) complexity, and supports keyed.
-
Do more with less — After tree shaking, project of hello world is only 1KB, but it has most fetures, virtual DOM, hooks API, functional component and more.
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'))
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
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>
)
}
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
return () => {
store.unsubscribe()
}
}, [])
More like useEffect, but useLayout is sync and blocking UI.
useLayout(() => {
document.title = 'count is ' + count
}, [flag])
useMemo
has the same rules 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
is based useMemo
, it will return a cached function.
const cb = useCallback(() => {
console.log('cb was cached')
}, [])
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 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"
}
]
_MIT @yisar