Skip to content

improve types #378

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

Merged
merged 1 commit 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
81 changes: 43 additions & 38 deletions src/reconcile.ts
Original file line number Diff line number Diff line change
@@ -2,7 +2,6 @@ import {
IFiber,
FreElement,
FC,
Attributes,
HTMLElementEx,
FreNode,
HookEffect,
@@ -23,10 +22,10 @@ export const enum TAG {
SVG = 1 << 4,
DIRTY = 1 << 5,
MOVE = 1 << 6,
REPLACE = 1 << 7
REPLACE = 1 << 7,
}

export const render = (vnode: FreElement, node: Node): void => {
export const render = (vnode: FreElement, node: Node) => {
rootFiber = {
node,
props: { children: vnode },
@@ -41,23 +40,24 @@ export const update = (fiber?: IFiber) => {
}
}

const reconcile = (fiber?: IFiber): boolean => {
const reconcile = (fiber?: IFiber) => {
while (fiber && !shouldYield()) fiber = capture(fiber)
if (fiber) return reconcile.bind(null, fiber)
if (fiber) return reconcile.bind(null, fiber) as typeof reconcile
return null
}

const memo = (fiber) => {
const memo = (fiber: IFiber) => {
if ((fiber.type as FC).memo && fiber.old?.props) {
let scu = (fiber.type as FC).shouldUpdate || shouldUpdate
if (!scu(fiber.props, fiber.old.props)) { // fast-fix
if (!scu(fiber.props, fiber.old.props)) {
// fast-fix
return getSibling(fiber)
}
}
return null
}

const capture = (fiber: IFiber): IFiber | undefined => {
const capture = (fiber: IFiber) => {
fiber.isComp = isFn(fiber.type)
if (fiber.isComp) {
const memoFiber = memo(fiber)
@@ -73,7 +73,7 @@ const capture = (fiber: IFiber): IFiber | undefined => {
return sibling
}

const getSibling = (fiber) => {
const getSibling = (fiber?: IFiber) => {
while (fiber) {
bubble(fiber)
if (fiber.dirty) {
@@ -87,7 +87,7 @@ const getSibling = (fiber) => {
return null
}

const bubble = fiber => {
const bubble = (fiber: IFiber) => {
if (fiber.isComp) {
if (fiber.hooks) {
side(fiber.hooks.layout)
@@ -96,40 +96,42 @@ const bubble = fiber => {
}
}


const shouldUpdate = (a, b) => {
const shouldUpdate = (
a: Record<string, unknown>,
b: Record<string, unknown>
) => {
for (let i in a) if (!(i in b)) return true
for (let i in b) if (a[i] !== b[i]) return true
}

const updateHook = <P = Attributes>(fiber: IFiber): any => {
const updateHook = (fiber: IFiber) => {
resetCursor()
currentFiber = fiber
let children = (fiber.type as FC<P>)(fiber.props)
let children = (fiber.type as FC)(fiber.props)
reconcileChidren(fiber, simpleVnode(children))
}

const updateHost = (fiber: IFiber): void => {
fiber.parentNode = (getParentNode(fiber) as any) || {}
const updateHost = (fiber: IFiber) => {
fiber.parentNode = getParentNode(fiber) || {}
if (!fiber.node) {
if (fiber.type === 'svg') fiber.lane |= TAG.SVG
fiber.node = createElement(fiber) as HTMLElementEx
fiber.node = createElement(fiber)
}
reconcileChidren(fiber, fiber.props.children)
}

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

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

const reconcileChidren = (fiber: any, children: FreNode): void => {
const reconcileChidren = (fiber: IFiber, children: FreNode) => {
let aCh = fiber.kids || [],
bCh = (fiber.kids = arrayfy(children) as any)
bCh = (fiber.kids = arrayfy(children))
const actions = diff(aCh, bCh)

for (let i = 0, prev = null, len = bCh.length; i < len; i++) {
@@ -156,46 +158,49 @@ function clone(a, b) {
b.old = a
}

export const arrayfy = arr => (!arr ? [] : isArr(arr) ? arr : [arr])
export const arrayfy = (arr: unknown) => (!arr ? [] : isArr(arr) ? arr : [arr])

const side = (effects: HookEffect[]): void => {
effects.forEach(e => e[2] && e[2]())
effects.forEach(e => (e[2] = e[0]()))
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) {
var actions = [],
aIdx = {},
bIdx = {},
key = v => v.key + v.type,
i, j;
key = (v) => v.key + v.type,
i,
j
for (i = 0; i < a.length; i++) {
aIdx[key(a[i])] = i;
aIdx[key(a[i])] = i
}
for (i = 0; i < b.length; i++) {
bIdx[key(b[i])] = i;
bIdx[key(b[i])] = i
}
for (i = j = 0; i !== a.length || j !== b.length;) {
var aElm = a[i], bElm = b[j];
for (i = j = 0; i !== a.length || j !== b.length; ) {
var aElm = a[i],
bElm = b[j]
if (aElm === null) {
i++;
i++
} else if (b.length <= j) {
removeElement(a[i])
i++;
i++
} else if (a.length <= i) {
actions.push({ op: TAG.INSERT, elm: bElm, before: a[i] })
j++;
j++
} else if (key(aElm) === key(bElm)) {
clone(aElm, bElm)
actions.push({ op: TAG.UPDATE })
i++; j++;
i++
j++
} else {
var curElmInNew = bIdx[key(aElm)]
var wantedElmInOld = aIdx[key(bElm)]
if (curElmInNew === undefined) {
removeElement(a[i])
i++;
i++
} else if (wantedElmInOld === undefined) {
actions.push({ op: TAG.INSERT, elm: bElm, before: a[i] })
j++
@@ -211,6 +216,6 @@ const diff = function (a, b) {
}

export const getCurrentFiber = () => currentFiber || null
export const isFn = (x: any): x is Function => typeof x === 'function'
export const isStr = (s: any): s is number | string =>
typeof s === 'number' || typeof s === 'string'
export const isFn = (x: unknown): x is Function => typeof x === 'function'
export const isStr = (s: unknown): s is number | string =>
typeof s === 'number' || typeof s === 'string'
7 changes: 3 additions & 4 deletions src/type.ts
Original file line number Diff line number Diff line change
@@ -28,8 +28,6 @@ export interface FreElement<P extends Attributes = any, T = string> {
key: string
}

export type HookTypes = 'list' | 'effect' | 'layout'

export interface Hooks {
list: HookList[]
layout: HookEffect[]
@@ -47,22 +45,23 @@ 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
parentNode: HTMLElementEx | {}
node: HTMLElementEx
kids?: any
dirty: boolean
parent?: IFiber<P>
sibling?: IFiber<P>
child?: IFiber<P>
ref?: Ref<HTMLElement | undefined>
old?: IFiber
hooks?: Hooks
action: any
props: P
lane: number
isComp: boolean
}

export type HTMLElementEx = HTMLElement & { last: IFiber | null }
export type HTMLElementEx = HTMLElement | Text | SVGElement

export type FreText = string | number
export type FreNode =