-
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
[7팀 김주광] [Chapter 1-3] React, Beyond the Basics #9
base: main
Are you sure you want to change the base?
Changes from 11 commits
0e90595
e5ff875
06d60ab
2c4167f
b719f07
0f42d81
9bfd803
b683d7b
4831e14
c3b6c48
4147b9e
f55908d
a7e01ea
98d6739
6e05985
73770a6
dfbf97b
4ef15a7
5505f30
46864f4
65f0398
5e0e5b8
85dfce5
ddc5891
d627fc0
d3ecfc0
89aa542
2d862e0
d2f990a
7d3118d
b23de5d
b0b1e81
0ef3b1d
b68e2c3
e0e1a64
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"singleQuote": false | ||
} |
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,22 @@ | ||
// - 재귀적으로 각 속성에 대해 deepEquals 호출 | ||
export function deepEquals<T>(objA: T, objB: T): boolean { | ||
return objA === objB; | ||
if (objA === objB) { | ||
return true; | ||
} | ||
// 2. 둘 다 객체인 경우: | ||
// - 배열인지 확인 | ||
if (Array.isArray(objA) && Array.isArray(objB)) { | ||
return objA.every((v, i) => deepEquals(v, objB[i])); | ||
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. 이부분에서도 길이가 같은지 체크하시면 더 안정적인 코드가 될 것 같아요! |
||
} | ||
|
||
// - 객체의 키 개수가 다른 경우 처리 | ||
if ( | ||
typeof objA === "object" && | ||
typeof objB === "object" && | ||
Object.keys(objA).length === Object.keys(objB).length | ||
) { | ||
return Object.keys(objA).every((key) => deepEquals(objA[key], objB[key])); | ||
} | ||
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. 저는 객체 타입이랑 객체 길이 분기 처리를 따로 해놨는데 같이 처리하니 깔끔하네요! 저도 나중에 같이 처리 하도록 수정해야겠습니다ㅎㅎ |
||
|
||
return false; | ||
} |
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. deepEquals와 코드의 구성이 조금 다른 걸로 보이는데 이렇게 구성하신 이유가 있을까요! |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,32 @@ | ||
export function shallowEquals<T>(objA: T, objB: T): boolean { | ||
return objA === objB; | ||
// 1. 두 값이 정확히 같은지 확인 (참조가 같은 경우) | ||
if (objA === objB) { | ||
return true; | ||
} | ||
|
||
// 2. 둘 중 하나라도 객체가 아닌 경우 처리 | ||
if ( | ||
typeof objA !== "object" || | ||
objA === null || | ||
typeof objB !== "object" || | ||
objB === null | ||
) { | ||
return false; | ||
} | ||
|
||
// 3. 키 개수 비교 | ||
const keys1 = Object.keys(objA); | ||
const keys2 = Object.keys(objB); | ||
if (keys1.length !== keys2.length) { | ||
return false; | ||
} | ||
|
||
// 4. 모든 키에 대해 얕은 비교 | ||
for (const key of keys1) { | ||
if (objA[key] !== objB[key]) { | ||
return false; | ||
} | ||
} | ||
|
||
return true; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,32 @@ | ||
/* eslint-disable @typescript-eslint/no-unused-vars */ | ||
import { shallowEquals } from "../equalities"; | ||
import { ComponentType } from "react"; | ||
import { ComponentType, createElement } from "react"; | ||
import { useRef } from "../hooks"; | ||
|
||
/** | ||
* memo HOC는 컴포넌트의 props를 얕은 비교하여 불필요한 리렌더링을 방지합니다. | ||
* HOC 란? | ||
* Higher-Order Component | ||
* 기본 컴포넌트에 기능 추가하여 업그레이드된 컴포넌트를 만들수 있다. | ||
*/ | ||
export function memo<P extends object>( | ||
Component: ComponentType<P>, | ||
_equals = shallowEquals, | ||
equals = shallowEquals, | ||
) { | ||
return Component; | ||
// 2. 메모이제이션된 컴포넌트 생성 | ||
const MemoizedComponent = (props: P) => { | ||
// 1. 이전 props를 저장할 ref 생성 | ||
const propsRef = useRef<P | null>(null); | ||
const componentRef = useRef<React.ReactElement | null>(null); | ||
|
||
// 3. equals 함수를 사용하여 props 비교 | ||
if (propsRef.current === null || !equals(props, propsRef.current)) { | ||
propsRef.current = props; | ||
// 4. props가 변경된 경우에만 새로운 렌더링 수행 | ||
componentRef.current = createElement(Component, props); | ||
} | ||
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. 저는 아예 컴포넌트를 반환하도록 |
||
|
||
return componentRef.current; | ||
}; | ||
|
||
return MemoizedComponent; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,12 @@ | ||
/* eslint-disable @typescript-eslint/no-unused-vars,@typescript-eslint/no-unsafe-function-type */ | ||
import { DependencyList } from "react"; | ||
import { useMemo } from "./useMemo"; | ||
|
||
export function useCallback<T extends Function>( | ||
factory: T, | ||
_deps: DependencyList, | ||
) { | ||
// 직접 작성한 useMemo를 통해서 만들어보세요. | ||
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. 구현 잘 해주셔서 주석 지워주셔도 될 것 같아요! |
||
return factory as T; | ||
|
||
return useMemo(() => factory, _deps); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,26 @@ | ||
/* eslint-disable @typescript-eslint/no-unused-vars */ | ||
import { DependencyList } from "react"; | ||
import { shallowEquals } from "../equalities"; | ||
import { useRef } from "./useRef"; | ||
|
||
export function useMemo<T>( | ||
factory: () => T, | ||
_deps: DependencyList, | ||
_equals = shallowEquals, | ||
): T { | ||
// 직접 작성한 useRef를 통해서 만들어보세요. | ||
return factory(); | ||
// memo 초기값 설정 | ||
const ref = useRef<{ | ||
deps: DependencyList; | ||
value: T; | ||
initialized: boolean; | ||
}>({ deps: [], value: undefined as T, initialized: false }); | ||
|
||
Comment on lines
+11
to
+16
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. ref를 하나로 구현하셨군요! 좋은 인사이트를 주셔서 감사합니다! |
||
//memo 의존성 검사 | ||
if (!ref.current.initialized || !_equals(_deps, ref.current.deps)) { | ||
ref.current.deps = _deps; | ||
ref.current.value = factory(); | ||
ref.current.initialized = true; | ||
} | ||
return ref.current.value; | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,4 +1,11 @@ | ||||||
import { useState } from "react"; | ||||||
|
||||||
export function useRef<T>(initialValue: T): { current: T } { | ||||||
// React의 useState를 이용해서 만들어보세요. | ||||||
return { current: initialValue }; | ||||||
const [ref] = useState<{ current: T }>({ current: initialValue }); | ||||||
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.
Suggested change
찾아보니 이렇게 선언하는걸 추천하더라구요! |
||||||
/** | ||||||
* ref.current를 통해 값이 변경이 가능한 이유 | ||||||
* ref(참조값)은 그대로 두고 .current (속성)을 변경하는 것이라 가능 | ||||||
*/ | ||||||
return ref; | ||||||
} |
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.
오.. 재귀 함수를 잘 이용하셔서 깔끔하게 작성하셨네요! 코드 잘보고 갑니다~