Fre
👻 Tiny React like framework with Concurrent.
Feature
- 🎉 Functional Component and hooks API
- 🎊 Time slicing and Algebraic effects
- 🔭 keyed reconcilation algorithm
Real world
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