Skip to content

Commit

Permalink
strict equality check
Browse files Browse the repository at this point in the history
  • Loading branch information
dderg committed Sep 5, 2023
1 parent 94a78c4 commit 399f4e2
Show file tree
Hide file tree
Showing 33 changed files with 227 additions and 204 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ module.exports = {
'import/no-cycle': 'error',
'no-unreachable': 'error',
'no-undef': 'error',
'eqeqeq': 'error',
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'error',
'react/jsx-uses-react': 'error',
Expand Down
6 changes: 5 additions & 1 deletion examples/benchmarking/src/listMemoFacet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const Performance = () => {

const tick = () => {
setDataFacet((data) => {
if (data == NO_VALUE) return []
if (data === NO_VALUE) return []

data[0].health = data[0].health === 10 ? 5 : 10
return data
Expand Down Expand Up @@ -50,6 +50,7 @@ const ListItem = ({ item }: { item: Facet<Data> }) => {
useFacetEffect(
(health) => {
randomWork(health)
return undefined
},
[],
[health],
Expand All @@ -58,6 +59,7 @@ const ListItem = ({ item }: { item: Facet<Data> }) => {
useFacetEffect(
(name) => {
randomWork(name)
return undefined
},
[],
[name],
Expand All @@ -66,6 +68,7 @@ const ListItem = ({ item }: { item: Facet<Data> }) => {
useFacetEffect(
(name) => {
randomWork(name)
return undefined
},
[],
[name],
Expand All @@ -74,6 +77,7 @@ const ListItem = ({ item }: { item: Facet<Data> }) => {
useFacetEffect(
(name) => {
randomWork(name)
return undefined
},
[],
[name],
Expand Down
2 changes: 1 addition & 1 deletion packages/@react-facet/core/src/components/Map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const Map = <T,>({ array, children, equalityCheck }: MapProps<T>) => {
<>
{times(
(index) =>
equalityCheck != null ? (
equalityCheck !== undefined ? (
<MapChildMemo<T>
key={index}
arrayFacet={array}
Expand Down
2 changes: 1 addition & 1 deletion packages/@react-facet/core/src/components/With.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const hasData = <T,>(_: Facet<T | null | undefined>, shouldRender: boolean | NoV
}

export const With = <T,>({ data, children }: WithProps<T>) => {
const shouldRenderFacet = useFacetMap((data) => data != null, [], [data])
const shouldRenderFacet = useFacetMap((data) => data !== undefined, [], [data])
const shouldRender = useFacetUnwrap(shouldRenderFacet)
return hasData(data, shouldRender) ? children(data) : null
}
8 changes: 4 additions & 4 deletions packages/@react-facet/core/src/createEqualityChecks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ export const createNullableEqualityCheck = <T>(comparator: EqualityCheck<T>) =>
let previous: T | null | undefined | NoValue = NO_VALUE

return (value: T | null | undefined) => {
if (value == null || previous == null) {
if (value != previous) {
if (value === undefined || value === null || previous === undefined || previous === null) {
if (value !== previous) {
previous = value
return false
} else {
Expand Down Expand Up @@ -90,7 +90,7 @@ export const createUniformArrayEqualityCheck =

let isEquals = true
for (let i = 0; i < longestLength; i++) {
if (previous[i] == null) {
if (previous[i] === undefined) {
previous[i] = comparator()
}
if (!previous[i](current[i])) {
Expand Down Expand Up @@ -158,7 +158,7 @@ export const createOptionalValueEqualityCheck =
let initializedComparator = comparator()

return (current: T | undefined | null) => {
if (current == null) {
if (current === undefined || current === null) {
if (previousWasNullish) {
return true
}
Expand Down
4 changes: 2 additions & 2 deletions packages/@react-facet/core/src/facet/createFacet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export function createFacet<V>({
const checker = equalityCheck?.()

const update = (newValue: V) => {
if (equalityCheck != null) {
if (equalityCheck !== undefined) {
// we optimize for the most common scenario of using the defaultEqualityCheck (by inline its implementation)
if (equalityCheck === defaultEqualityCheck) {
const typeofValue = typeof newValue
Expand All @@ -37,7 +37,7 @@ export function createFacet<V>({
return
}
} else {
if (checker != null && checker(newValue)) {
if (checker !== undefined && checker(newValue)) {
return
}
}
Expand Down
3 changes: 2 additions & 1 deletion packages/@react-facet/core/src/helpers/hasDefinedValue.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { NoValue, NO_VALUE, Value } from '../types'

export const hasDefinedValue = (value: Value | NoValue): value is Value => value != null && value !== NO_VALUE
export const hasDefinedValue = (value: Value | NoValue): value is Value =>
value !== undefined && value !== null && value !== NO_VALUE
6 changes: 3 additions & 3 deletions packages/@react-facet/core/src/helpers/multiObserve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ export function multiObserve<Y extends Facet<unknown>[], T extends [...Y]>(
for (let i = 0; i < facets.length; i++) {
unsubscribes[i] = facets[i].observe((value) => {
values[i] = value
hasAllDependencies = hasAllDependencies || values.every((value) => value != NO_VALUE)
hasAllDependencies = hasAllDependencies || values.every((value) => value !== NO_VALUE)

if (hasAllDependencies) {
if (cleanup != null) {
if (cleanup !== undefined) {
cleanup()
}

Expand All @@ -42,7 +42,7 @@ export function multiObserve<Y extends Facet<unknown>[], T extends [...Y]>(
for (let index = 0; index < unsubscribes.length; index++) {
unsubscribes[index]()
}
if (cleanup != null) {
if (cleanup !== undefined) {
cleanup()
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/@react-facet/core/src/hooks/useFacetCallback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export function useFacetCallback<M, Y extends Facet<unknown>[], T extends [...Y]
const values = facets.map((facet) => facet.get())

for (const value of values) {
if (value === NO_VALUE) return defaultReturnValue != null ? defaultReturnValue : NO_VALUE
if (value === NO_VALUE) return defaultReturnValue !== undefined ? defaultReturnValue : NO_VALUE
}

return callbackMemoized(...(values as ExtractFacetValues<T>))(...(args as K))
Expand Down
14 changes: 7 additions & 7 deletions packages/@react-facet/core/src/hooks/useFacetEffect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@ import { cancelScheduledTask, scheduleTask } from '../scheduler'

export const createUseFacetEffect = (useHook: typeof useEffect | typeof useLayoutEffect) => {
return function <Y extends Facet<unknown>[], T extends [...Y]>(
effect: (...args: ExtractFacetValues<T>) => void | Cleanup,
effect: (...args: ExtractFacetValues<T>) => undefined | Cleanup,
dependencies: unknown[],
facets: T,
) {
// eslint-disable-next-line react-hooks/exhaustive-deps
const effectMemoized = useCallback(effect as (...args: unknown[]) => ReturnType<typeof effect>, dependencies)

useHook(() => {
let cleanup: void | Cleanup
let cleanup: undefined | Cleanup

if (facets.length === 1) {
const unsubscribe = facets[0].observe((value) => {
if (cleanup != null) {
if (cleanup !== undefined) {
cleanup()
}

Expand All @@ -25,7 +25,7 @@ export const createUseFacetEffect = (useHook: typeof useEffect | typeof useLayou

return () => {
unsubscribe()
if (cleanup != null) {
if (cleanup !== undefined) {
cleanup()
}
}
Expand All @@ -36,10 +36,10 @@ export const createUseFacetEffect = (useHook: typeof useEffect | typeof useLayou
const values: unknown[] = facets.map(() => NO_VALUE)

const task = () => {
hasAllDependencies = hasAllDependencies || values.every((value) => value != NO_VALUE)
hasAllDependencies = hasAllDependencies || values.every((value) => value !== NO_VALUE)

if (hasAllDependencies) {
if (cleanup != null) {
if (cleanup !== undefined) {
cleanup()
}

Expand All @@ -61,7 +61,7 @@ export const createUseFacetEffect = (useHook: typeof useEffect | typeof useLayou
return () => {
cancelScheduledTask(task)
unsubscribes.forEach((unsubscribe) => unsubscribe())
if (cleanup != null) {
if (cleanup !== undefined) {
cleanup()
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/@react-facet/core/src/hooks/useFacetPropSetter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export function useFacetPropSetter<T extends Record<string, any>, Prop extends k
): PropSetter<T, Prop> {
return useMemo(
() => (value: T[Prop]) => {
facet.setWithCallback((prev) => ({ ...(prev != NO_VALUE ? prev : {}), [prop]: value } as unknown as T))
facet.setWithCallback((prev) => ({ ...(prev !== NO_VALUE ? prev : {}), [prop]: value } as unknown as T))
},
[facet, prop],
)
Expand Down
3 changes: 2 additions & 1 deletion packages/@react-facet/core/src/hooks/useFacetRef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ export function useFacetRef<T>(facet: Facet<T>): MutableRefObject<Option<T>>
export function useFacetRef<T>(facet: Facet<T>, defaultValue: T): MutableRefObject<T>
export function useFacetRef<T>(facet: Facet<T>, defaultValue?: T): MutableRefObject<T> {
let value = facet.get()
if (value === NO_VALUE && defaultValue != undefined) {
if (value === NO_VALUE && defaultValue !== undefined) {
value = defaultValue
}

const ref = useRef<Option<T>>(value)
useFacetEffect(
(value) => {
ref.current = value
return undefined
},
[],
[facet],
Expand Down
2 changes: 1 addition & 1 deletion packages/@react-facet/core/src/hooks/useFacetWrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export function useFacetWrap<T extends Value>(
[is],
)

if (inlineFacet == null) {
if (inlineFacet === undefined) {
return prop as Facet<T>
} else {
inlineFacet.set(prop as T)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ export function mapIntoObserveArray<M>(
let hasAllDependencies = false

const task =
checker == null
checker === undefined
? () => {
hasAllDependencies = hasAllDependencies || dependencyValues.every((value) => value != NO_VALUE)
hasAllDependencies = hasAllDependencies || dependencyValues.every((value) => value !== NO_VALUE)
if (!hasAllDependencies) return

const result = fn(...dependencyValues)
Expand All @@ -28,7 +28,7 @@ export function mapIntoObserveArray<M>(
}
: equalityCheck === defaultEqualityCheck
? () => {
hasAllDependencies = hasAllDependencies || dependencyValues.every((value) => value != NO_VALUE)
hasAllDependencies = hasAllDependencies || dependencyValues.every((value) => value !== NO_VALUE)
if (!hasAllDependencies) return

const result = fn(...dependencyValues)
Expand All @@ -52,7 +52,7 @@ export function mapIntoObserveArray<M>(
listener(result)
}
: () => {
hasAllDependencies = hasAllDependencies || dependencyValues.every((value) => value != NO_VALUE)
hasAllDependencies = hasAllDependencies || dependencyValues.every((value) => value !== NO_VALUE)
if (!hasAllDependencies) return

const result = fn(...dependencyValues)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export function mapIntoObserveSingle<T, M>(
equalityCheck?: EqualityCheck<M>,
): Observe<M> {
// Most common scenario is not having any equality check
if (equalityCheck == null) {
if (equalityCheck === undefined) {
return (listener: Listener<M>) => {
return facet.observe((value: T) => {
const result = fn(value)
Expand Down
7 changes: 6 additions & 1 deletion packages/@react-facet/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,12 @@ export type Cleanup = Unsubscribe
export type StartSubscription<V> = (update: Update<V>) => Cleanup

export const isFacet = <T>(value: Value | Facet<T>): value is Facet<T> => {
return value != null && (value as Facet<T>).observe != null && (value as Facet<T>).get != null
return (
value !== null &&
value !== undefined &&
(value as Facet<T>).observe !== undefined &&
(value as Facet<T>).get !== undefined
)
}

export type FacetProp<T extends Value> = Facet<T> | ExcludeFacetFactory<T>
Expand Down
2 changes: 1 addition & 1 deletion packages/@react-facet/deferred-mount/src/index.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ describe('DeferredMountWithCallback', () => {

const runRaf = () => {
const cb = frames.pop()
if (cb != null) act(() => cb())
if (cb !== undefined) act(() => cb())
}

const MOUNT_COMPLETION_DELAY = 1000
Expand Down
6 changes: 3 additions & 3 deletions packages/@react-facet/deferred-mount/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ interface DeferredMountProps {
*/
export function DeferredMount({ children }: DeferredMountProps) {
const pushDeferUpdateFunction = useContext(pushDeferUpdateContext)
const [deferred, setDeferred] = useState(pushDeferUpdateFunction != null)
const [deferred, setDeferred] = useState(pushDeferUpdateFunction !== undefined)

useEffect(() => {
if (pushDeferUpdateFunction) pushDeferUpdateFunction(setDeferred)
Expand All @@ -198,12 +198,12 @@ export const useNotifyMountComplete = () => useContext(NotifyMountComplete)
*/
export function DeferredMountWithCallback({ children }: DeferredMountWithCallbackProps) {
const pushDeferUpdateFunction = useContext(pushDeferUpdateContext)
const [deferred, setDeferred] = useState(pushDeferUpdateFunction != null)
const [deferred, setDeferred] = useState(pushDeferUpdateFunction !== undefined)
const resolveMountComplete = useRef<(value: void | PromiseLike<void>) => void>()
const mountCompleteBeforeInitialization = useRef(false)

const onMountComplete = useCallback(() => {
if (resolveMountComplete.current != null) {
if (resolveMountComplete.current !== undefined) {
resolveMountComplete.current()
} else {
mountCompleteBeforeInitialization.current = true
Expand Down
4 changes: 2 additions & 2 deletions packages/@react-facet/dom-components/src/Div.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ export const Div = ({ style, className, id, children, innerRef, ...handlers }: D
const ref = innerRef ?? defaultRef

useSetProp(className, (value) => {
if (ref.current == null) return
if (ref.current === null) return
ref.current.className = value ?? ''
})

useSetProp(id, (value) => {
if (ref.current == null) return
if (ref.current === null) return
ref.current.id = value ?? ''
})

Expand Down
6 changes: 3 additions & 3 deletions packages/@react-facet/dom-components/src/Img.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,17 @@ export const Img = ({ style, className, id, src, innerRef, ...handlers }: ImgPro
const ref = innerRef ?? defaultRef

useSetProp(className, (value) => {
if (ref.current == null) return
if (ref.current === null) return
ref.current.className = value ?? ''
})

useSetProp(id, (value) => {
if (ref.current == null) return
if (ref.current === null) return
ref.current.id = value ?? ''
})

useSetProp(src, (value) => {
if (ref.current == null) return
if (ref.current === null) return
ref.current.setAttribute('src', value ?? '')
})

Expand Down
Loading

0 comments on commit 399f4e2

Please sign in to comment.