Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve types #379

Merged
merged 2 commits into from
Mar 11, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 8 additions & 9 deletions src/commit.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { Ref } from './type'
import { IFiber, Ref } from './type'
import { updateElement } from './dom'
import { isFn, TAG } from './reconcile'


export const commit = (fiber: any) => {
if (!fiber) {
return
@@ -32,24 +31,24 @@ export const commit = (fiber: any) => {
}

const refer = (ref?: Ref<HTMLElement | undefined>, dom?: HTMLElement) => {
if (ref)
isFn(ref) ? ref(dom) : ref.current = dom
if (ref) isFn(ref) ? ref(dom) : (ref.current = dom)
}

const kidsRefer = (kids: any) => {
kids.forEach(kid => {
const kidsRefer = (kids: IFiber[]) => {
kids.forEach((kid) => {
kid.kids && kidsRefer(kid.kids)
refer(kid.ref, null)
})
}

export const removeElement = fiber => {
export const removeElement = (fiber: IFiber) => {
if (fiber.isComp) {
fiber.hooks && fiber.hooks.list.forEach(e => e[2] && e[2]())
fiber.hooks && fiber.hooks.list.forEach((e) => e[2] && e[2]())
fiber.kids.forEach(removeElement)
} else {
// @ts-expect-error
fiber.parentNode.removeChild(fiber.node)
kidsRefer(fiber.kids)
refer(fiber.ref, null)
}
}
}
20 changes: 12 additions & 8 deletions src/h.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { isStr, arrayfy } from './reconcile'
import { FC, FreElement } from './type'
import { FC, FreNode, FreText, IFiber } from './type'

// for jsx2
export const h = (type, props: any, ...kids) => {
export const h = (type: string | FC, props: any, ...kids: FreNode[]) => {
props = props || {}
kids = flat(arrayfy(props.children || kids))

@@ -17,10 +17,11 @@ export const h = (type, props: any, ...kids) => {
return createVnode(type, props, key, ref)
}

const some = (x: unknown) => x != null && x !== true && x !== false
const some = <T>(x: T | boolean | null | undefined): x is T =>
x != null && x !== true && x !== false

const flat = (arr: any[], target = []) => {
arr.forEach(v => {
const flat = (arr: FreNode[], target: IFiber[] = []) => {
arr.forEach((v) => {
isArr(v)
? flat(v, target)
: some(v) && target.push(isStr(v) ? createText(v) : v)
@@ -35,14 +36,17 @@ export const createVnode = (type, props, key, ref) => ({
ref,
})

export const createText = (vnode: any) =>
({ type: '#text', props: { nodeValue: vnode + '' } } as FreElement)
export const createText = (vnode: FreText) =>
({ type: '#text', props: { nodeValue: vnode + '' } } as IFiber)

export function Fragment(props) {
return props.children
}

export function memo<T extends object>(fn: FC<T>, compare?: FC<T>['shouldUpdate']) {
export function memo<T extends object>(
fn: FC<T>,
compare?: FC<T>['shouldUpdate']
) {
fn.memo = true
fn.shouldUpdate = compare
return fn
14 changes: 7 additions & 7 deletions src/hook.ts
Original file line number Diff line number Diff line change
@@ -22,15 +22,15 @@ export const resetCursor = () => {
cursor = 0
}

export const useState = <T>(initState: T): [T, Dispatch<SetStateAction<T>>] => {
return useReducer(null, initState)
export const useState = <T>(initState: T) => {
return useReducer<T, SetStateAction<T>>(null, initState)
}

export const useReducer = <S, A>(
reducer?: Reducer<S, A>,
initState?: S
): [S, Dispatch<A>] => {
const [hook, current]: [any, IFiber] = getHook<HookReducer>(cursor++)
const [hook, current] = getHook<HookReducer>(cursor++)
if (hook.length === 0) {
hook[0] = initState
hook[1] = (value: A | Dispatch<A>) => {
@@ -45,22 +45,22 @@ export const useReducer = <S, A>(
}
}
}
return hook
return hook as Required<HookReducer>
}

export const useEffect = (cb: EffectCallback, deps?: DependencyList): void => {
export const useEffect = (cb: EffectCallback, deps?: DependencyList) => {
return effectImpl(cb, deps!, 'effect')
}

export const useLayout = (cb: EffectCallback, deps?: DependencyList): void => {
export const useLayout = (cb: EffectCallback, deps?: DependencyList) => {
return effectImpl(cb, deps!, 'layout')
}

const effectImpl = (
cb: EffectCallback,
deps: DependencyList,
key: 'effect' | 'layout'
): void => {
) => {
const [hook, current] = getHook<HookEffect>(cursor++)
if (isChanged(hook[1], deps)) {
hook[0] = cb
27 changes: 12 additions & 15 deletions src/reconcile.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
import {
IFiber,
FreElement,
FC,
HTMLElementEx,
FreNode,
HookEffect,
} from './type'
import { IFiber, FC, HookEffect, FreNode, Child, FreText } from './type'
import { createElement } from './dom'
import { resetCursor } from './hook'
import { schedule, shouldYield } from './schedule'
@@ -25,7 +18,7 @@ export const enum TAG {
REPLACE = 1 << 7,
}

export const render = (vnode: FreElement, node: Node) => {
export const render = (vnode: IFiber, node: Node) => {
rootFiber = {
node,
props: { children: vnode },
@@ -120,16 +113,19 @@ const updateHost = (fiber: IFiber) => {
reconcileChidren(fiber, fiber.props.children)
}

const simpleVnode = (type: any) =>
isStr(type) ? createText(type as string) : type
const simpleVnode = (type: IFiber | FreText) =>
isStr(type) ? createText(type) : type

const getParentNode = (fiber: IFiber) => {
while ((fiber = fiber.parent)) {
if (!fiber.isComp) return fiber.node
}
}

const reconcileChidren = (fiber: IFiber, children: FreNode) => {
const reconcileChidren = (
fiber: IFiber,
children: IFiber | IFiber[] | null | undefined
) => {
let aCh = fiber.kids || [],
bCh = (fiber.kids = arrayfy(children))
const actions = diff(aCh, bCh)
@@ -150,23 +146,24 @@ const reconcileChidren = (fiber: IFiber, children: FreNode) => {
}
}

function clone(a, b) {
function clone(a: IFiber, b: IFiber) {
b.hooks = a.hooks
b.ref = a.ref
b.node = a.node // 临时修复
b.kids = a.kids
b.old = a
}

export const arrayfy = (arr: unknown) => (!arr ? [] : isArr(arr) ? arr : [arr])
export const arrayfy = <T>(arr: T | T[] | null | undefined) =>
!arr ? [] : isArr(arr) ? arr : [arr]

const side = (effects: HookEffect[]) => {
effects.forEach((e) => e[2] && e[2]())
effects.forEach((e) => (e[2] = e[0]()))
effects.length = 0
}

const diff = function (a, b) {
const diff = function (a: IFiber[], b: IFiber[]) {
var actions = [],
aIdx = {},
bIdx = {},
33 changes: 9 additions & 24 deletions src/type.ts
Original file line number Diff line number Diff line change
@@ -10,24 +10,18 @@ export type Ref<T = any> = RefCallback<T> | RefObject<T> | null

export interface Attributes extends Record<string, any> {
key?: Key
children?: FreNode
ref?: Ref
children?: FreNode
}

export interface FC<P extends Attributes = {}> {
(props: P): FreElement<P> | null
(props: P): IFiber | FreText | null | undefined
fiber?: IFiber
type?: string
memo?: boolean
shouldUpdate?: (newProps: P, oldProps: P) => boolean
}

export interface FreElement<P extends Attributes = any, T = string> {
type: T
props: P
key: string
}

export interface Hooks {
list: HookList[]
layout: HookEffect[]
@@ -44,11 +38,11 @@ export type HookReducer<V = any, A = any> = [value: V, dispatch: Dispatch<A>]

export interface IFiber<P extends Attributes = any> {
key?: string
type: string | FC<P>
parentNode: HTMLElementEx | {}
node: HTMLElementEx
kids?: any
dirty: boolean
type?: string | FC<P>
parentNode?: HTMLElementEx | {}
node?: HTMLElementEx
kids?: IFiber[]
dirty?: boolean
parent?: IFiber<P>
sibling?: IFiber<P>
child?: IFiber<P>
@@ -64,23 +58,14 @@ export interface IFiber<P extends Attributes = any> {
export type HTMLElementEx = HTMLElement | Text | SVGElement

export type FreText = string | number
export type FreNode =
| FreText
| FreElement
| FreNode[]
| boolean
| null
| undefined
export type FreNode = Child[] | Child
export type Child = IFiber | FreText | null | undefined | boolean
export type SetStateAction<S> = S | ((prevState: S) => S)
export type Dispatch<A> = (value: A) => void
export type Reducer<S, A> = (prevState: S, action: A) => S
export type EffectCallback = () => any | (() => () => any)
export type DependencyList = ReadonlyArray<unknown>

export interface PropsWithChildren {
children?: FreNode
}

export type ITaskCallback = (() => ITaskCallback) | null

export interface ITask {