👻 Tiny React16 like library with Concurrent mode and Suspense.
- 🎉 Functional Component and hooks API
- 🎊 Concurrent mode (also called time slicing) and Suspense
- 🔭 keyed reconcilation (also called diff) algorithm
Fre (pronounced /fri:/
, like free) is a tiny and perfect js library, It means Free! ~
Package | Version | About |
---|---|---|
Fre |
fre core | |
Fard |
mini-program with fre | |
use-routes |
router for fre |
Thanks for Rasmus Schultz
yarn add fre
import { h, render, useState } from "fre"
function Counter() {
const [count, setCount] = useState(0)
return (
<div>
<h1>{count}</h1>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
)
}
render(<Counter />, 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 Counter() {
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>
)
}
render(<Counter />, document.getElementById("root"))
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 Counter() {
const [state, dispatch] = useReducer(reducer, { count: 1 })
return (
<div>
{state.count}
<button onClick={() => dispatch({ type: "up" })}>+</button>
<button onClick={() => dispatch({ type: "down" })}>+</button>
</div>
)
}
render(<Counter />, document.getElementById("root"))
useEffect
takes two parameters, the first is a effect callback and the second is an array
if the array changed, the callback will execute after commitWork, such as pureComponentDidUpdate
if the array is empty, it means execute once, such as componentDidMount
if no array, it means execute every time , such as componentDidUpdate
if useEffect returns a function, the function will execute before next commitWork, such as componentWillUnmount
function Counter({ 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>
)
}
render(<Counter />, document.getElementById("root"))
useCallback
has the same parameters as useEffect
, but useCallback
will return a cached function.
const set = new Set()
function Counter() {
const [count, setCount] = useState(0)
const cb = useCallback(() => {
console.log("cb was cached")
}, [count])
set.add(cb)
return (
<div>
<h1>{set.size}</h1>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
)
}
useMemo
has the same parameters as useEffect
, but useMemo
will return a cached value.
function Counter() {
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>
)
}
render(<Counter />, document.getElementById("root"))
useRef
will return a object which contains current node.
import { useRef, useEffect } from "fre"
function Counter() {
useEffect(() => {
console.log(t) // { current:<div>t</div> }
})
const t = useRef(null)
return <div ref={t}>t</div>
}
render(<Counter />, document.getElementById("root"))
functionalComponent is a new components scheme
function App() {
const [count, setCount] = useState(0)
return (
<div>
<h1>{count}</h1>
<button onClick={() => setCount(count + 1)}>+</button>
<Sex count={count} />
</div>
)
}
function Sex(props) {
const [sex, setSex] = useState("boy")
return (
<div>
<h2>{props.count}</h2>
<h1>{sex}</h1>
<button
onClick={() => {
sex === "boy" ? setSex("girl") : setSex("boy")
}}
>
x
</button>
</div>
)
}
render(<App />, document.getElementById("root"))
Props are used for component communication
function App() {
const [sex, setSex] = useState("boy")
return (
<div>
<Sex sex={sex} />
<button onClick={() => (sex === "boy" ? setSex("girl") : setSex("boy"))} />
</div>
)
}
function Sex(props) {
return <div>{props.sex}</div>
}
Props contains children to render all the child elements of itself
const HelloBox = () => (
<Box>
<h1>Hello world !</h1>
</Box>
)
const Box = props => <div>{props.children}</div>
Hooks do not support HOC and extends, but render props are supported by default
const HelloBox = () => <Box render={value => <h1>{value}</h1>} />
const Box = props => <div>{props.render("hello world!")}</div>
Also can be render children
const HelloBox = () => (
<Box>
{value => {
return <h1>{value}</h1>
}}
</Box>
)
const Box = props => <div>{props.children("hello world!")}</div>
If you want to rewrite any function, please use options, such as:
options.end = false
options.commitWork = fiber => {
// something you will rewrite commitWork
}
The default export h function needs to be configured
import { h } from "fre"
{
"plugins": [["transform-react-jsx", { "pragma": "h" }]]
}
If browser environment, recommend to use htm
Fre implements a tiny priority scheduler, which like react Fiber.
It can break the work, and when there are idle time, the work will continue.
Concurrent Mode is also called time slicing
or concurrent mode
.
Suspense is another way to break the work.
It throws promise, and fre catches promise then suspend the work. It waits until resolve to the promise.
Fre implements a compact reconcilation algorithm support keyed, which also called diff.
It uses hash to mark locations to reduce much size.