Skip to content

Instantly share code, notes, and snippets.

@InfiniteXyy
Created June 18, 2021 08:28
Show Gist options
  • Save InfiniteXyy/eac1aa80ff99a7a3235ec27d0d15254d to your computer and use it in GitHub Desktop.
Save InfiniteXyy/eac1aa80ff99a7a3235ec27d0d15254d to your computer and use it in GitHub Desktop.
use factory api for ayanami
import { Injectable } from '@asuka/di'
import { Ayanami, ImmerReducer, useAyanami, Effect, EffectAction } from 'ayanami'
import type { Draft } from 'immer'
import React from 'react'
import { Observable } from 'rxjs'
import { map, delay } from 'rxjs/operators'
type ActionBuilder<State extends Record<string, any>> = Record<string, (draft: Draft<State>, arg: any) => void>
type EffectBuilder<State extends Record<string, any>, Actions extends Record<string, (...args: any) => void>> = Record<
string,
(this: Ayanami<State> & Actions, arg: Observable<any>) => Observable<EffectAction>
>
type ModuleFactory<
State extends Record<string, any> = {},
Actions extends Record<string, (...args: any) => void> = {}
> = {
actions<A extends ActionBuilder<State>>(actions: A): ModuleFactory<State, A & Actions>
effects<E extends EffectBuilder<State, Actions>>(effects: E): ModuleFactory<State, E & Actions>
build(): { new (...args: any[]): Ayanami<State> & { [K in keyof Actions]: Actions[K] } }
}
function defineAyanami<State extends Record<string, any>>(state: State, name?: string): ModuleFactory<State> {
const module = Injectable()(
class extends Ayanami<State> {
defaultState = state
},
)
name && Object.defineProperty(module, 'name', { value: name, writable: false })
const factory = {
effects: (methods: Record<string, Function>) => {
Object.keys(methods).forEach((key) => {
module.prototype[key] = methods[key]
Effect()(module.prototype, key, Object.getOwnPropertyDescriptor(module, key)!)
})
return factory
},
actions: (actions: Record<string, Function>) => {
Object.keys(actions).forEach((key) => {
module.prototype[key] = actions[key]
ImmerReducer()(module.prototype, key, Object.getOwnPropertyDescriptor(module, key)!)
})
return factory
},
build: () => module,
}
return factory
}
// YOUR CODE STARTS HERE
const CounterModule = defineAyanami({ count: 0 }, 'CounterModule')
.actions({
add: (state, amount: number) => (state.count += amount),
})
.effects({
asyncAdd(payload: Observable<number>) {
return payload.pipe(
delay(150),
map((count) => this.getActions().add(count)),
)
},
})
.build()
export const Apps = () => {
const [{ count }, { asyncAdd }] = useAyanami(CounterModule)
return <div onClick={() => asyncAdd(1)}>{count}</div>
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment