-
Notifications
You must be signed in to change notification settings - Fork 62
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
[8팀 김도운] [Chapter 1-3] React, Beyond the Basics #14
base: main
Are you sure you want to change the base?
Changes from all commits
2445113
02285b7
02c1577
87d46b9
b8d6a1c
1e6091f
8029238
40cf1f4
a3edc99
3635214
e64ae2a
532fcb7
154f9fe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,43 @@ | ||
import { isObject } from "../utils"; | ||
|
||
export function deepEquals<T>(objA: T, objB: T): boolean { | ||
if (Object.is(objA, objB)) { | ||
return true; | ||
} | ||
|
||
if (Array.isArray(objA) && Array.isArray(objB)) { | ||
return _deepEqualArray(objA, objB); | ||
} | ||
|
||
if (isObject(objA) && isObject(objB)) { | ||
return _deepEqualObject( | ||
objA as Record<string | number | symbol, unknown>, | ||
objB as Record<string | number | symbol, unknown>, | ||
); | ||
} | ||
|
||
return objA === objB; | ||
} | ||
|
||
function _deepEqualArray<T>(arrA: Array<T>, arrB: Array<T>): boolean { | ||
if (arrA.length !== arrB.length) return false; | ||
return arrA.every((item, index) => deepEquals(item, arrB[index])); | ||
} | ||
|
||
function _deepEqualObject<T extends string | number | symbol>( | ||
objA: Record<T, unknown>, | ||
objB: Record<T, unknown>, | ||
): boolean { | ||
if (objA === objB) return true; | ||
|
||
const keysA = Object.keys(objA) as T[]; | ||
const keysB = Object.keys(objB) as T[]; | ||
|
||
if (keysA.length !== keysB.length) { | ||
return false; | ||
} | ||
|
||
return keysA.every( | ||
(key) => keysB.includes(key) && deepEquals(objA[key], objB[key]), | ||
); | ||
} | ||
Comment on lines
+22
to
+43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 크 이렇게 배열 비교와 객체 비교 함수를 따로 분리해서 구현해주신점 너무 좋습니다bb There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 혹시 배열일 경우를 따로 분리하신 이유가 있을까요? |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,46 @@ | ||
import { isObject } from "../utils"; | ||
|
||
export function shallowEquals<T>(objA: T, objB: T): boolean { | ||
return objA === objB; | ||
if (Object.is(objA, objB)) return true; | ||
|
||
if (Array.isArray(objA) && Array.isArray(objB)) { | ||
return _shallowEqualArray(objA, objB); | ||
} | ||
|
||
if (isObject(objA) && isObject(objB)) { | ||
return _shallowEqualObject( | ||
objA as Record<string, unknown>, | ||
objB as Record<string, unknown>, | ||
); | ||
} | ||
|
||
return false; | ||
} | ||
|
||
function _shallowEqualArray<T>(arrA: Array<T>, arrB: Array<T>): boolean { | ||
if (arrA.length !== arrB.length) return false; | ||
return arrA.every((item, index) => item === arrB[index]); | ||
} | ||
|
||
function _shallowEqualObject<T extends string | number | symbol>( | ||
objA: Record<T, unknown>, | ||
objB: Record<T, unknown>, | ||
): boolean { | ||
if (objA === objB) return true; | ||
|
||
const keysA = Object.keys(objA) as T[]; | ||
const keysB = Object.keys(objB) as T[]; | ||
|
||
if (keysA.length !== keysB.length) { | ||
return false; | ||
} | ||
|
||
for (const key of keysA) { | ||
if ( | ||
!Object.prototype.hasOwnProperty.call(objB, key) || | ||
objA[key] !== objB[key] | ||
) | ||
return false; | ||
} | ||
return true; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,24 @@ | ||
/* eslint-disable @typescript-eslint/no-unused-vars */ | ||
import { shallowEquals } from "../equalities"; | ||
import { ComponentType } from "react"; | ||
import { ComponentType, createElement, ReactElement } from "react"; | ||
import { useRef } from "../hooks"; | ||
|
||
export function memo<P extends object>( | ||
Component: ComponentType<P>, | ||
_equals = shallowEquals, | ||
) { | ||
return Component; | ||
const MemoizedComponent = (props: P) => { | ||
const prevPropRef = useRef<P | null>(null); | ||
const prevComponentRef = useRef<ReactElement<P> | null>(null); | ||
|
||
const shouldUpdate = | ||
prevPropRef.current === null || !_equals(prevPropRef.current, props); | ||
|
||
prevPropRef.current = props; | ||
if (shouldUpdate) { | ||
prevComponentRef.current = createElement(Component, props); | ||
} | ||
|
||
return prevComponentRef.current; | ||
}; | ||
return MemoizedComponent; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,11 @@ | ||
/* eslint-disable @typescript-eslint/no-unused-vars,@typescript-eslint/no-unsafe-function-type */ | ||
/* eslint-disable @typescript-eslint/no-unsafe-function-type */ | ||
import { DependencyList } from "react"; | ||
import { useMemo } from "./useMemo.ts"; | ||
|
||
export function useCallback<T extends Function>( | ||
factory: T, | ||
_deps: DependencyList, | ||
) { | ||
// 직접 작성한 useMemo를 통해서 만들어보세요. | ||
return factory as T; | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
return useMemo(() => factory, _deps); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { createContext, useContext } from "react"; | ||
import { | ||
NotificationContextType, | ||
ThemeContextType, | ||
UserContextType, | ||
} from "../types"; | ||
|
||
export const UserContext = createContext<UserContextType | undefined>( | ||
undefined, | ||
); | ||
export const NotificationContext = createContext< | ||
NotificationContextType | undefined | ||
>(undefined); | ||
export const ThemeContext = createContext<ThemeContextType | undefined>( | ||
undefined, | ||
); | ||
|
||
export const useUserContext = () => { | ||
const context = useContext(UserContext); | ||
if (context === undefined) { | ||
throw new Error("useAppContext must be used within an AppProvider"); | ||
} | ||
return context; | ||
}; | ||
|
||
export const useNotificationContext = () => { | ||
const context = useContext(NotificationContext); | ||
if (context === undefined) { | ||
throw new Error("useAppContext must be used within an AppProvider"); | ||
} | ||
return context; | ||
}; | ||
|
||
export const useThemeContext = () => { | ||
const context = useContext(ThemeContext); | ||
if (context === undefined) { | ||
throw new Error("useAppContext must be used within an AppProvider"); | ||
} | ||
return context; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
여기서 바로 keysB.includes(key)를 사용하는게 keysB 배열을 매 키마다 전체 검색할 것 같아 보이네요 혹시 Set을 사용하는 것이 어떤가요??
이렇게 써볼 수 있을 것 같습니다!