Fre
👻 Fast 1kB React like library with the same hooks API
Feature
- 🎉 really functionalComponent and hooks API
- 🎊 Async rendering like react Fiber and keyed diff algorithm
- 🔭 minimal but perfect , fast 1 KB , no dependences
Introduction
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 |
Use
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'))
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 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
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
useEffect
takes two parameters, the first is a effect callback and the second is an array, usually props
When the array changes, the effect callback will run after commitWork, such as pureComponentDidUpdate
if the array is empty, it means use once, such as componentDidMount
if the second is undefined, it means use every time , such as componentDidUpdate
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
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
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'))
useContext
Context is the state of external create, internal use
When it changes, all components that own useContext
will rerender
const ctx = createContext(0)
function App() {
const [count, setCount] = useContext(ctx)
return (
<div>
<h1>{count}</h1>
<button onClick={() => setCount(count + 1)}>+</button>
<Other />
</div>
)
}
function Other() {
const count = useContext(ctx)[0]
return <h1>{count}</h1>
}
FunctionalComponent
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
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>
HOC
Does not support HOC but you can renturn a function wrapped another function.
function App() {
return HOC(() => <div>I am wrapped by a HOC</div>)
}
options
If you want to rewrite any function, please use options, such as:
options.end = false
options.commitWork = fiber => {
// something you will rewrite commitWork
}
JSX
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 supports most JSX syntax, if-else
is also Ok but need to be careful.
{
isShow && <A />
isShow ? <A /> : null
isShow ? <A /> : <B />
}
because there no key
for them, please use it as late as possible.
Async rendering
Fre use requestAnimationFrame
to process update queue, It like react Fiber but tinier than.
Async rendering is also called time slicing
.
keyed diff
Fre implements a compact diff algorithm support keyed
It uses hash to mark locations for easy comparison
License
MIT ©132yse inspired by anu