Skip to content

Commit 86cc221

Browse files
authored
Merge pull request #377 from cyfaboop/master
improve hook types
2 parents 302ad63 + a71af98 commit 86cc221

File tree

3 files changed

+52
-42
lines changed

3 files changed

+52
-42
lines changed

src/hook.ts

+36-29
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
1-
import { update, isFn, getCurrentFiber } from "./reconcile"
1+
import { update, isFn, getCurrentFiber } from './reconcile'
22
import {
33
DependencyList,
44
Reducer,
55
IFiber,
66
Dispatch,
77
SetStateAction,
88
EffectCallback,
9-
HookTypes,
109
RefObject,
11-
IEffect,
1210
FreNode,
13-
} from "./type"
11+
HookList,
12+
HookEffect,
13+
HookReducer,
14+
HookMemo,
15+
} from './type'
1416

1517
const EMPTY_ARR = []
1618

@@ -28,15 +30,15 @@ export const useReducer = <S, A>(
2830
reducer?: Reducer<S, A>,
2931
initState?: S
3032
): [S, Dispatch<A>] => {
31-
const [hook, current]: [any, IFiber] = getHook<S>(cursor++)
33+
const [hook, current]: [any, IFiber] = getHook<HookReducer>(cursor++)
3234
if (hook.length === 0) {
3335
hook[0] = initState
3436
hook[1] = (value: A | Dispatch<A>) => {
3537
let v = reducer
3638
? reducer(hook[0], value as any)
3739
: isFn(value)
38-
? value(hook[0])
39-
: value
40+
? value(hook[0])
41+
: value
4042
if (hook[0] !== v) {
4143
hook[0] = v
4244
update(current)
@@ -47,31 +49,31 @@ export const useReducer = <S, A>(
4749
}
4850

4951
export const useEffect = (cb: EffectCallback, deps?: DependencyList): void => {
50-
return effectImpl(cb, deps!, "effect")
52+
return effectImpl(cb, deps!, 'effect')
5153
}
5254

5355
export const useLayout = (cb: EffectCallback, deps?: DependencyList): void => {
54-
return effectImpl(cb, deps!, "layout")
56+
return effectImpl(cb, deps!, 'layout')
5557
}
5658

5759
const effectImpl = (
5860
cb: EffectCallback,
5961
deps: DependencyList,
60-
key: HookTypes
62+
key: 'effect' | 'layout'
6163
): void => {
62-
const [hook, current] = getHook(cursor++)
64+
const [hook, current] = getHook<HookEffect>(cursor++)
6365
if (isChanged(hook[1], deps)) {
6466
hook[0] = cb
6567
hook[1] = deps
66-
current.hooks[key].push(hook)
68+
current.hooks[key].push(hook as Required<HookEffect>)
6769
}
6870
}
6971

7072
export const useMemo = <S = Function>(
7173
cb: () => S,
7274
deps?: DependencyList
7375
): S => {
74-
const hook = getHook<S>(cursor++)[0]
76+
const hook = getHook<HookMemo>(cursor++)[0]
7577
if (isChanged(hook[1], deps!)) {
7678
hook[1] = deps
7779
return (hook[0] = cb())
@@ -90,39 +92,37 @@ export const useRef = <T>(current: T): RefObject<T> => {
9092
return useMemo(() => ({ current }), [])
9193
}
9294

93-
export const getHook = <S = Function | undefined, Dependency = any>(
94-
cursor: number
95-
): [[S, Dependency], IFiber] => {
95+
export const getHook = <T extends HookList = HookList>(cursor: number) => {
9696
const current: IFiber<any> = getCurrentFiber()
9797
const hooks =
9898
current.hooks || (current.hooks = { list: [], effect: [], layout: [] })
9999
if (cursor >= hooks.list.length) {
100-
hooks.list.push([] as IEffect)
100+
hooks.list.push([] as any)
101101
}
102-
return [(hooks.list[cursor] as unknown) as [S, Dependency], current]
102+
return [hooks.list[cursor], current] as unknown as [Partial<T>, IFiber]
103103
}
104104

105105
export type ContextType<T> = {
106-
({ value, children }: { value: T, children: FreNode }): FreNode;
107-
initialValue: T;
106+
({ value, children }: { value: T; children: FreNode }): FreNode
107+
initialValue: T
108108
}
109109

110-
type SubscriberCb = () => void;
110+
type SubscriberCb = () => void
111111

112112
export const createContext = <T>(initialValue: T): ContextType<T> => {
113113
const contextComponent: ContextType<T> = ({ value, children }) => {
114114
const valueRef = useRef(value)
115115
const subscribers = useMemo(() => new Set<SubscriberCb>(), EMPTY_ARR)
116116

117117
if (valueRef.current !== value) {
118-
valueRef.current = value;
118+
valueRef.current = value
119119
subscribers.forEach((subscriber) => subscriber())
120120
}
121121

122122
return children
123123
}
124-
contextComponent.initialValue = initialValue;
125-
return contextComponent;
124+
contextComponent.initialValue = initialValue
125+
return contextComponent
126126
}
127127

128128
export const useContext = <T>(contextType: ContextType<T>): T => {
@@ -132,16 +132,19 @@ export const useContext = <T>(contextType: ContextType<T>): T => {
132132

133133
useEffect(() => {
134134
return () => subscribersSet && subscribersSet.delete(triggerUpdate)
135-
}, EMPTY_ARR);
135+
}, EMPTY_ARR)
136136

137137
let contextFiber = getCurrentFiber().parent
138138
while (contextFiber && contextFiber.type !== contextType) {
139139
contextFiber = contextFiber.parent
140140
}
141141

142142
if (contextFiber) {
143-
const hooks = contextFiber.hooks.list as unknown as [[RefObject<T>], [Set<SubscriberCb>]]
144-
const [[value], [subscribers]] = hooks;
143+
const hooks = contextFiber.hooks.list as unknown as [
144+
[RefObject<T>],
145+
[Set<SubscriberCb>]
146+
]
147+
const [[value], [subscribers]] = hooks
145148

146149
subscribersSet = subscribers.add(triggerUpdate)
147150

@@ -151,6 +154,10 @@ export const useContext = <T>(contextType: ContextType<T>): T => {
151154
}
152155
}
153156

154-
export const isChanged = (a: DependencyList, b: DependencyList) => {
155-
return !a || a.length !== b.length || b.some((arg, index) => !Object.is(arg, a[index]))
157+
export const isChanged = (a: DependencyList | undefined, b: DependencyList) => {
158+
return (
159+
!a ||
160+
a.length !== b.length ||
161+
b.some((arg, index) => !Object.is(arg, a[index]))
162+
)
156163
}

src/reconcile.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
Attributes,
66
HTMLElementEx,
77
FreNode,
8-
IEffect,
8+
HookEffect,
99
} from './type'
1010
import { createElement } from './dom'
1111
import { resetCursor } from './hook'
@@ -158,7 +158,7 @@ function clone(a, b) {
158158

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

161-
const side = (effects: IEffect[]): void => {
161+
const side = (effects: HookEffect[]): void => {
162162
effects.forEach(e => e[2] && e[2]())
163163
effects.forEach(e => (e[2] = e[0]()))
164164
effects.length = 0

src/type.ts

+14-11
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,19 @@ export interface FreElement<P extends Attributes = any, T = string> {
3030

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

33-
export interface IHook {
34-
list: IEffect[]
35-
layout: IEffect[]
36-
effect: IEffect[]
33+
export interface Hooks {
34+
list: HookList[]
35+
layout: HookEffect[]
36+
effect: HookEffect[]
3737
}
38-
39-
export type IRef = (
40-
e: HTMLElement | undefined
41-
) => void | { current?: HTMLElement }
38+
export type HookList = HookMemo | HookEffect | HookReducer
39+
export type HookMemo<V = any> = [value: V, deps: DependencyList]
40+
export type HookEffect = [
41+
cb: EffectCallback,
42+
deps: DependencyList,
43+
cleanup?: () => any
44+
]
45+
export type HookReducer<V = any, A = any> = [value: V, dispatch: Dispatch<A>]
4246

4347
export interface IFiber<P extends Attributes = any> {
4448
key?: string
@@ -51,15 +55,14 @@ export interface IFiber<P extends Attributes = any> {
5155
sibling?: IFiber<P>
5256
child?: IFiber<P>
5357
ref?: Ref<HTMLElement | undefined>
54-
hooks: IHook
58+
hooks?: Hooks
5559
action: any
5660
props: P
5761
lane: number
5862
isComp: boolean
5963
}
6064

6165
export type HTMLElementEx = HTMLElement & { last: IFiber | null }
62-
export type IEffect = [Function?, number?, cleanup?: Function]
6366

6467
export type FreText = string | number
6568
export type FreNode =
@@ -72,7 +75,7 @@ export type FreNode =
7275
export type SetStateAction<S> = S | ((prevState: S) => S)
7376
export type Dispatch<A> = (value: A) => void
7477
export type Reducer<S, A> = (prevState: S, action: A) => S
75-
export type EffectCallback = () => void | (() => void | undefined)
78+
export type EffectCallback = () => any | (() => () => any)
7679
export type DependencyList = ReadonlyArray<unknown>
7780

7881
export interface PropsWithChildren {

0 commit comments

Comments
 (0)