Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions Chapter_3/Jae0/useCallback.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
## useCallback

`useMemo` 에서는 전달 받은 `Callback` 의 `return` 값을 메모이제이션 한것과 유사하게

💡 `useCallback` 은 전달받은 `Callback` 함수 자체를 저장하여 함수를 메모이제이션 함
⇒ 즉 특정 함수를 새로 만들지 않고 다시 재사용한다는 의미를 가짐

useMemo와의 차이점은 저장하고자 하는 값이 변수냐 함수냐의 차이 일뿐

`const memoFuncName = useCallback( Callback , [ ] )`

- **첫 번째 인자**

변수는 인자로 전달받은 `Function`을 메모이제이션해 값을 가지고 있게 됨

- **두 번째 인자**
Array로 Array 안의 내부의 값이 변경되지 않는 이상 변경되지 않음!

**주의점**

🔥 함수 내부의 전역 변수를 받아 사용하는 로직이 존재한다면 해당 변수를 디펜던시 안에 넣어줘야함!
105 changes: 105 additions & 0 deletions Chapter_3/Jae0/useContext.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
> **Prop Drilling & Context**
>
> 만약 최 상위 Component 가 지니고 있는 상태를 깊이 존재하는 하위 Component에게 전달하기
>
> 위해서는 중간에 존재하는 Component들의 prop을 통해 전달 > 전달 > 전달 > 전달을 통해
>
> 주고 받아야하는 복잡한 문제가 발생! - 문제는 하위에서 최상위로 전달할 때도 동일한 문제가 발생함
>
> 이런 문제는 깊어지고 상태가 많아질수록 데이터 관리에 불편하고,
>
> 중간에 state가 의도와 다르게 변경될 수 있는 위험성을 초래함
>
> 이런 과정을 PropDrilling이라고함
>
> 그리고 이런 prop drilling을 극복하기 위해 등장한 개념이 Context 임

💡 이런 Prop Drilling을 개선하기 위해 Redux Recoil 등의 라이브러리가 존재하고,

Context API는 React 라이브러리에서 기본으로 제공되는 상태 주입 API로
상위 컴포넌트에서 만들어진 Context를 통해 하위 컴포넌트가 상태를 쉽게 사용가능하게 함

- 상태를 주입하는 역할을 할뿐 다른 라이브러리처럼 상태 관리를 해주는 API가 아님
- 🔥 Context API는 특정 상태를 통해 다른 상태를 만들수 없으며,
필요에 따라 이러한 상태 변화를 최적화 할 수 없기 때문에 상태관리 라이브러리가 아님
- 최상단에 Context provider를 지정하기보다는 범위를 좁히고 좁혀 사용하는것이 좋음

**사용 방법**

```jsx
// Context 생성

import { createContext, useState } from "react";

// createContext 를 통해 Context를 만들어줌
export const Context = createContext();

// component를 umbrella로 감싸줄 외부 Wrap component 함수 만들기.
export function ContextProvider({ children }) {
// conText에서 사용할 기본 State 지정
const [State, setState] = useState(false);

// 상태를 변경할 Function
const Toggle = () => setState((state) => !state);

return (
<Context.Provider
{/* 기본 상태와 상태변경을 위한 함수를 객체로 전달한다 */}
value={{ state, ToggleDarkMode }}>
{/* 기본 상태와 상태변경을 위한 함수를 객체로 전달한다 */}
{children}
</Context.Provider>
)
}

// Context 위치 선언
export default function App() {
// 앞서 만든 해당 Context component로 감싸 주기
return (
<ContextProvider>
<childComponent />
</ContextProvider>
)
}

// 하위 Component

export default function ChildComponent (){
// useContext 를 통해 Context 불러오기
const { State, Toggle } = useContext(Context);

return (
<div className='Button'>
{ state }
<button onClick={() => ToggleDarkMode()}> Toggle!</button>
</div>
)
}
```

**ContextAPI 오류 검증**

- 만약 하위 컴포넌트에서 Context를 제대로 불러오지 못했을 때를 대비한 방어 코드

```tsx
export default function ChildComponent() {
// useContext 를 통해 Context 불러오기

function checkContext() {
const context = useContext(Context);
if (context === undefined) {
throw new Error("context가 불려오지 못함");
}
return context;
}

const { state, toggle } = checkContext();

return (
<div className="Button">
{state}
<button onClick={() => ToggleDarkMode()}> Toggle!</button>
</div>
);
}
```
113 changes: 113 additions & 0 deletions Chapter_3/Jae0/useEffect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
💡 무엇인가 변화가 생겨날 대 변화를 감지하고 반응하는 Hook

주로 화면에 처음 렌더링될때 , 다시 렌더링되는순간 , 사라지는순간 에 특정 작업을 처리하고 싶을때 사용함

```jsx
useEffect(() => {
// code
}, [value]);
```

**첫 번째 인자**

Callback 함수를 전달받고,

Callback함수 내부에 실행하고 싶은 코드를 작성하면 됨

**두 번째 인자**

dependency Arr 를 전달받고 내부에는 값(value)을 전달 할 수 있음

- 전달받은 값(value)이 변화 되어질 때 마다 useEffect 내부의 Callback 함수가 실행되어짐

🔥 useEffect는 특별한 기능을 통해 값을 감시하지 않고,

렌더링이 새롭게 될 때마다 의존성에 존재하는 값을 보며 의존성의 값이 이전 값과 다를때

전달받은 Callback 함수를 실행하게 된다.

- 일부 외부 데이터와 동기화 하려는것이 아니라면 사용하지 않음
- Component의 최상위 위치에서만 선언할 수 있음
- strict 모드에서는 useEffect가 2번 실행 되어짐

### 의존성

``

의존성 배열 조차 전달하지 않는 경우 의존성을 비교할 필요 없이 렌더링 될 때마다 callback이 실행됨

⇒ 주로 component가 렌더링 된것을 확인하고싶을 때 사용함

```jsx
// 렌더링 테스트 코드
useEffect(()=>{
console.log("렌더링 발생"
})
```

🔥 그렇다면 왜 아무것도 전달하지 않고 사용할까?

1. useEffect는 component가 렌더링이 완료된 후 실행되어지고, 일반 함수는 렌더링 도중 실행되어짐
2. 서버 사이드 렌더링 관점에서 useEffect는 클라이언트 사이드에서 실행되는것을 보장함

`[]`

빈 배열을 전달한 경우 React에서는 비교할 의존성이 없다고 판단하고 최초 렌더링 직후에만 실행되어짐

### 주의, 권장 사항

- useEffect가 전달 받는 callback에 기명 함수를 사용하는것을 권장함

⇒ 많은 useEffect들이 생겨나고 이를 구분하기위해 사용하기 좋음

```jsx
useEffect(function 이름() {}, []);
```

- useEffect는 가능한 작고 가볍게 만들수록 좋음

- dependency에는 외부에서 생성된 객체, 함수와 같은 참조값을 사용하면 안된다

```jsx
function ChatRoom({ roomId }) {
const [message, setMessage] = useState('');

const options = {
serverUrl: serverUrl,
roomId: roomId
};

useEffect(() => {
const connection = createConnection(options);
connection.connect();
return () => connection.disconnect();
}, [options]);
// ...
```

위의 예시처럼 options 를 감시하고 있다면,
만약 options의 데이터가 변하지 않은 상태에서 다른 이유로 rerender가 발생했을때 원하는 의도는
useEffect가 다시 실행되지 않는 것을 의도함.
하지만 🔥 options는 참조 데이터 이기때문에 rerender시에 값의 변화가 없어도 참조 주소가 변경됨
따라서 useEffect는 참조 주소가 변경된것을 변화로 감지하고 useEffect가 실행되어짐

### Clean Up

💡 이전 값을 기준으로 실행되며, 이전 상태를 청소해주는 역할

```jsx
useEffect(() => {
element.addEventListener();

return () => {
element.removeEventListener();
// clean up zone
};
});
```

clean up 작업은 useEffect 에 전달한 callback 함수의 return 함수 내부에서 실행되어짐

🔥 즉 useEffect 내부의 callback이 실행될 때 이전 clean up 함수가 존재한다면

clean up 함수를 실행 한 뒤 callback 함수를 실행함
48 changes: 48 additions & 0 deletions Chapter_3/Jae0/useState.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
💡 State ? 리액트에서 component 가 지니고 있는 상태를 의미함

```jsx
const [state, setState] = useState(initailState);
const [num, setNum] = useState(0);
```

내부의 state는 원하는 이름으로 변경 시켜 줄 수 있음

state

현재의 상태값은 배열 첫번 째 아이템인 state 내부에 들어있음

setState

상태를 변경 시켜주고싶을때 사용할 수 있는 함수

initailState

해당 state의 초기값을 전달할 수 있음

만약 전달된 초기값이 없다면 `undefined`

- setState 를 이용해 state를 변경시켜주면 해당 component 는 다시 한 번 렌더링이 진행됨
- state를 사용하지 않고 내부에 변수를 통해 상태를 관리하게된다면, 매번 렌더링이 다시 이루어질때
해당 함수형 component는 매번 실행되어지고 내부 변수의 변화된 값은 매번 초기화됨
- state가 자신의 state를 렌더링이 되어도 유지할 수 있는 이유는 closer

### 게으른 초기화

💡 `useState`에 변수 대신 함수를 넘기는 방법을 게으른 초기화 라고 함

```jsx
// 일반적 사용 방법
const [state,setState] = useState(Number.parseInt(window.localStorage ... ))
// 해당 로직은 state가 처음 실행되는 순간에도 복잡한 연산을 실행함
// 그리고 값이 변경되어 다시 리렌더링 되는 순간에도 다시 복잡한 연산을 실행하게됨

// 게으른 초기화
const [state,setState] = useState(()=>{
return Number.parseInt(window.localStorage.getItem(key))
})
```

- 기본적으로 게으른 초기화를 사용하는 순간은 주로 무거운 연산을 포함하고 있을때 사용을 권장함
⇒ 렌더링이 다시 발생하면 인수로 전달한 실행 값이 다시 실행되기 때문
⇒ 배열에 대한 접근 `map` `filter` `find` 등 / Storage에 접근
- 게으른 초기화 함수는 오로지 state가 처음 만들어지는 순간에만 사용됨