-
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
[11팀 임재도] [Chapter 1-3] React, Beyond the Basics #41
Open
effozen
wants to merge
19
commits into
hanghae-plus:main
Choose a base branch
from
effozen:try/1
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
ab2c1df
[Feat] : Equals 로직 구현
effozen 5467181
[Feat] : memo 기능 구현
effozen 794b675
[Feat] : memo lint 수정
effozen 65f6387
[Feat] : useRef 구현
effozen c6b4813
[Feat] : useMemo 구현
effozen 12cbc39
[Feat] : useMemo Lint 수정
effozen 4d74132
[Feat] : useCallback 구현
effozen 628e87d
[Feat] : 타입 분리
effozen d186c31
[Feat] : useAppContext 훅 분리
effozen f12bfe3
[Feat] : 컴포넌트 분리 및 베럴파일 생성
effozen ad41140
[Feat] : useMemo를 이용해서 최적화 적용
effozen fbadc5f
Fix : App.tsx 에러 수정
effozen c6af837
[Feat] : AppContext 분리
effozen 830f4ef
[Feat] : AppContext 분리를 컴포넌트에 반영
effozen 07b4ad9
[Refactor] : 포메팅
effozen 2a6c98a
[Feat] : Advanced Test 코드 통과 / 컴포넌트 구조 확립
effozen 70f3b90
[Refactor] : , 추가
effozen 8bcc1b7
[Feat] : 내가 만든 코드로 useCallback, useMemo, memo 등 대체
effozen e1b31d5
[refactor] : lint 수정
effozen File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,51 @@ | ||
export function deepEquals<T>(objA: T, objB: T): boolean { | ||
return objA === objB; | ||
// 1. 기본 타입이거나 null인 경우 처리 | ||
// primitive type 외에는 모두 Object를 상속받음. | ||
// symbole은 deepEquals 시 비교 X -> 필요시 추후 구현 | ||
// Q. 그냥 objA === objB로 비교해도 되지 않나? | ||
if ( | ||
typeof objA !== "object" || | ||
objA === null || | ||
typeof objB !== "object" || | ||
objB === null | ||
) { | ||
return objA === objB; | ||
} | ||
|
||
// 2. 둘 다 객체인 경우: | ||
// - 배열인지 확인 | ||
// - 객체의 키 개수가 다른 경우 처리 | ||
// - 재귀적으로 각 속성에 대해 deepEquals 호출 | ||
if (Array.isArray(objA) && Array.isArray(objB)) { | ||
if (objA.length !== objB.length) { | ||
return false; | ||
} | ||
|
||
for (let i = 0; i < objA.length; i++) { | ||
if (!deepEquals(objA[i], objB[i])) { | ||
return false; | ||
} | ||
} | ||
} else { | ||
// 두 객체의 키 개수가 다른 경우 | ||
const keysA = Object.keys(objA) as (keyof T)[]; | ||
const keysB = Object.keys(objB) as (keyof T)[]; | ||
|
||
if (keysA.length !== keysB.length) { | ||
return false; | ||
} | ||
|
||
for (const key of keysA) { | ||
if ( | ||
// general하게 사용되는 deepEquals이므로, Object.prototype.hasOwnProperty를 사용 (call로 매핑해줌으로써, 예외상황을 처리) | ||
!Object.prototype.hasOwnProperty.call(objB, key) || | ||
!deepEquals(objA[key], objB[key]) | ||
) { | ||
return false; | ||
} | ||
} | ||
} | ||
Comment on lines
+15
to
+47
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 true; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,37 @@ | ||
export function shallowEquals<T>(objA: T, objB: T): boolean { | ||
return objA === objB; | ||
// 두 객체의 참조 레퍼런스 값이 같은 경우, 또는 기본 타입인데 같은 경우 | ||
if (objA === objB) { | ||
return true; | ||
} | ||
|
||
// 두 객체 중 하나라도 객체가 아니거나 null인 경우 | ||
if ( | ||
typeof objA !== "object" || | ||
objA === null || | ||
typeof objB !== "object" || | ||
objB === null | ||
) { | ||
return false; | ||
} | ||
|
||
// 두 객체의 키 개수가 다른 경우 | ||
const keysA = Object.keys(objA) as (keyof T)[]; | ||
const keysB = Object.keys(objB) as (keyof T)[]; | ||
|
||
if (keysA.length !== keysB.length) { | ||
return false; | ||
} | ||
|
||
// 모든 키에 대해서 얕은 비교 수행 | ||
// general하게 사용되는 shallowEquals이므로, Object.prototype.hasOwnProperty를 사용 (call로 매핑해줌으로써, 예외상황을 처리) | ||
for (const key of keysA) { | ||
if ( | ||
!Object.prototype.hasOwnProperty.call(objB, key) || | ||
objA[key] !== objB[key] | ||
Comment on lines
+29
to
+30
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; | ||
} | ||
} | ||
|
||
return true; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,22 @@ | ||
/* eslint-disable @typescript-eslint/no-unused-vars */ | ||
import { shallowEquals } from "../equalities"; | ||
import { ComponentType } from "react"; | ||
import React, { ComponentType, ReactNode } from "react"; | ||
|
||
export function memo<P extends object>( | ||
Component: ComponentType<P>, | ||
_equals = shallowEquals, | ||
) { | ||
return Component; | ||
// ref에 대한 의문, hooks가 아닌데, ref를 사용하는게 맞는가? -> hooks라는 전제를 깔자. | ||
// TODO : 이거 관련해서 다시 한번 깊게 탐구해보기. Ref가 진짜로 필요한가? 그리고, 만약 클로져로 처리했을 때 리랜더링이 안일어나나? | ||
// let preProps = useRef<P | null>(null); | ||
let preProps: P | null = null; | ||
let memoizedComponent: ReactNode | null = null; | ||
|
||
return function (props: P) { | ||
if (preProps === null || !_equals(preProps, props)) { | ||
preProps = props; | ||
// jsx 였으면, 컴포넌트 생성해도 좋았겠지만, 결국 이것도 오버헤드일 것 같기에 createElement로 진행 | ||
memoizedComponent = React.createElement(Component, props); | ||
} | ||
return memoizedComponent; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"; | ||
|
||
export function useCallback<T extends Function>( | ||
factory: T, | ||
_deps: DependencyList, | ||
) { | ||
// 직접 작성한 useMemo를 통해서 만들어보세요. | ||
return factory as T; | ||
const memoizedFactory = useMemo(() => factory, _deps); | ||
return memoizedFactory as T; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,23 @@ | ||
/* 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(); | ||
const prevDeps = useRef<DependencyList | null>(null); | ||
const prevResult = useRef<T | null>(null); | ||
|
||
if ( | ||
prevResult.current === null || | ||
prevDeps.current === null || | ||
!_equals(prevDeps.current, _deps) | ||
) { | ||
prevDeps.current = _deps; | ||
prevResult.current = factory(); | ||
} | ||
|
||
return prevResult.current; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,8 @@ | ||
import { useState } from "react"; | ||
|
||
export function useRef<T>(initialValue: T): { current: T } { | ||
// React의 useState를 이용해서 만들어보세요. | ||
return { current: initialValue }; | ||
// useRef, useState 모두 컴포넌트의 라이프사이클 동안 값을 유지하는 게 필요함. | ||
// useState는 값의 변동이 있을 때 리랜더링이 일어남. 참조의 경우도 참조값이 변해야 함. 그래서, useState의 기본 기능을 활용하되, 참조값을 업데이트 하지 않는 방식으로 구현. | ||
const [refObject] = useState({ current: initialValue }); | ||
return refObject; | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
오 기본형 데이터를 한 번에 처리하신 것 같은데 이렇게 합칠 수도 있군요!👍