a lightweight react framework based on react 、redux and middleware
约束原则
- 采用分层原则,职责分离
- controller 与 view 一一对应,处理相应的业务逻辑
- redux store 中只维护业务数据实体
- 视图交互相关的 state 维护在 controller
- effects 应该维护在相应的 controller
- 不应该 dispatch 异步 action
更多请看这里关于框架分层设计的思考
- model
- reducers:维护与服务端一致的数据实体
- controller
- controller:是一个自定义 hook,无需考虑复用,因为 controller 与 view 一一对应
- event binding
- hook
- effect
- dispatch sync action
- store selector
- view
- 与 controller 一一对应,保持 view 的简单性
- application
- router config
- redux config
- app life cycle
- middlewares:支持同步或异步中间件。
- jsb sdk
- report sdk
- error sdk
- perf sdk
- ...
- fetch controller:缓存,http 规范,错误处理等
- middleware
- fetch error
- before fetch
- after fetch
- sw fetch cache
- middleware
- base
- hooks:通用 hook
- components:通用组件
- middleware plugins
yarn add @jarzzzi/wolverine
- index
constapp=newWolverine({appMode: 'spa',routerMode: 'hashRouter'})app.configReducers(reducers)app.configRoutes(routes)app.onError((error,ctx)=>{console.log('app error',error)})app.onDidmount((ctx)=>{console.log('app didmount',ctx)consthandle=(state: any)=>{console.log('route change',state)}constcleanup=ctx.on('routeChange',handle)return()=>{cleanup()}})app.onUnmount((ctx)=>{console.log('app unmount',ctx)})app.use((ctx)=>{returnimport('./plugins/reportsdk').then(({default: reporter})=>{ctx.reporter=reporterreturn()=>{console.log('cleanup reporter')}})})app.render(document.getElementById('root'))- reducer
exportdefaultcreateModel({namespace: 'counter',state: {count: 0},reducers: {inc(state,{payload: count}){return{
...state,count: count}},dec(state,{payload: count}){return{
...state,count: count}},fetch(state,{payload: count}){return{
...state,count: count}}},})- controller
exportdefaultfunctionuseController(props){const[loading,setLoading]=useState(false)constdispatch=useDispatch()const{ count }=useSelector((store)=>{const{ counter }=storereturn{count: counter.count}})constonInc=()=>{dispatch({type: 'counter/inc',payload: count+1})}constonDec=()=>{dispatch({type: 'counter/dec',payload: count-1})}constonFetch=async()=>{setLoading(true)constres=awaitfetch('xxx')setLoading(false)dispatch({type: 'counter/fetch',payload: res})}constonReport=async()=>{appContext.ready('reporter').then((reporter)=>{reporter.push()})}return{
count,
onInc,
onDec,
onFetch,
onReport
}}- view
exportdefaultReact.memo((props)=>{const{
count,
onDec,
onInc,
onFetch,
onReport,}=useController(props)return(<div><div>{count}</div><div><buttononClick={onInc}>inc</button></div><div><buttononClick={onDec}>dec</button></div><div><buttononClick={onFetch}>fetch</button></div><div><buttononClick={onReport}>report</button></div></div>)})- immutable data
