Concurrent Mode — This is an amazing idea, which implements the coroutine scheduler in JavaScript, it also called Time slicing.
Keyed reconcilation algorithm — Fre has a minimal diff algorithm, It supported keyed, pre-process, offscreen rendering and SSR hydration.
Do more with less — Fre get the tiny size, but it has most features, virtual DOM, hooks API, Suspense, Fragments, Fre.memo and so on.
https://deepwiki.com/frejs/fre
yarn add freimport{render,useState}from'fre'functionApp(){const[count,setCount]=useState(0)return<><h1>{count}</h1><buttononClick={()=>setCount(count+1)}>+</button></>}render(<App/>,document.body)useState is a base API, It will receive initial state and return an Array
You can use it many times, new state is available when component is rerender
functionApp(){const[up,setUp]=useState(0)const[down,setDown]=useState(()=>0)return(<><h1>{up}</h1><buttononClick={()=>setUp(up+1)}>+</button><h1>{down}</h1><buttononClick={()=>setDown(down-1)}>-</button></>)}useReducer and useState are almost the same,but useReducer needs a global reducer
functionreducer(state,action){switch(action.type){case'up':
return{count: state.count+1}case'down':
return{count: state.count-1}}}functionApp(){const[state,dispatch]=useReducer(reducer,{count: 1})return(<>{state.count}<buttononClick={()=>dispatch({type: 'up'})}>+</button><buttononClick={()=>dispatch({type: 'down'})}>-</button></>)}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
functionApp({ flag }){const[count,setCount]=useState(0)useEffect(()=>{document.title='count is '+count},[flag])return(<><h1>{count}</h1><buttononClick={()=>setCount(count+1)}>+</button></>)}If it returns a function, the function can do cleanups:
useEffect(()=>{document.title='count is '+countreturn()=>{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.
constmemo=(c)=>(props)=>useMemo(()=>c,[Object.values(props)])useCallback is based useMemo, it will return a cached function.
constcb=useCallback(()=>{console.log('cb was cached.')},[])useRef will return a function or an object.
functionApp(){useEffect(()=>{console.log(t)// { current:<div>t</div> }})constt=useRef(null)return<divref={t}>t</div>}If it uses a function, it can return a cleanup and executes when removed.
functionApp(){constt=useRef((dom)=>{if(dom){doSomething()}else{cleanUp()}})returnflag&&<spanref={t}>I will removed</span>}import{createContext,useContext}from'fre';constThemeContext=createContext(null);functionApp(){return(<ThemeContextvalue="dark"><Button/></ThemeContext>)}functionButton({ children }){consttheme=useContext(ThemeContext);constclassName='button-'+theme;return(<buttonclass={className}>{children}</button>);}constHello=lazy('./hello.js')exportfunctionApp(){return(<div><Suspensefallback={<div>loading...</div>}><Hello/><div>world!</div></Suspense></div>)}functionA(){thrownewError('render error test')}exportfunctionApp(){return(<div><ErrorBoundaryfallback={<div>occur an error</div>}><A/></ErrorBoundary></div>)}// fragmentfunctionApp(){return<>{something}</>}// render arrayfunctionApp(){return[a,b,c]}For vite example
exportdefault{esbuild: {jsxFactory: 'h',jsxFragment: 'Fragment',jsxInject: `import { h, Fragment } from 'fre'`,target: 'es2020',format: 'esm'}}MIT @yisar
