Skip to content
forked from frejs/fre

👻 Fast 1kB React16 like library with the same hooks API.

License

Notifications You must be signed in to change notification settings

mindplay-dk/fre

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

fre logo

Fre

👻 Fast 1kB React like library with the same hooks API

npm-v npm-d gzip

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 npm fre core
Fard npm mini-program with fre
use-routes npm 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

About

👻 Fast 1kB React16 like library with the same hooks API.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 100.0%