useReducer
useReducer는 리액트 내장 훅 중 하나로, 상태관리와 관련된 훅 입니다.
복잡한 상태 로직을 다룰 때 매우 유용합니다.
단순한 상태 변화보다 다양한 액션타입에 따라 상태를 다르게 업데이트 하고 싶을 때 많이 사용됩니다
useReducer은 어떤 상황에서 사용할까??
컴포넌트 상태 관리 방법에는 여러가지가 있습니다
가장 기본적인 방법 >> useState
But, 상태 로직이 복잡해지면 useState 만으로 관리하기 어려운 경우가 많습니다
ex) 여러 개의 관련된 상태를 업데이트 해야 하거나, 상태 업데이트 로직이 복잡한 경우
> 이럴 때 useReducer가 useState 보다 더 적합합니다
useReducer을 사용하면 상태와 상태 업데이트 로직을 하나의 함수로 일관되게 관리할 수 있어 가독성과 유지보수성이 향상됩니다
useReducer의 내부 로직을 이해하기 위해서는 useReducer의 세 요소를 알고 있어야 합니다
reducer > 상태 업데이트 로직을 담고있는 함수로 현재 상태와 액션을 받아 새로운 상태를 반환한다. 순수함수여야 하며, 주어진 입력에 대해 항상 동일한 출력을 반환해야 합니다
dispatch > Reducer에게 특정 액션을 전달하는 역할을 한다. 액션은 상태 업데이트를 트리거하는 객체로, 타입(type)과 필요에 따라 추가 데이터를 포함할 수 있다. dispatch를 호출할 때 액션 객체를 인자로 전달합니다
action > 상태 업데이트의 구체적인 내용을 담고 있는 객체이다. 보통 type 속성을 가지며, 상태를 어떻게 업데이트 할지를 나타냅니다
요약 : dispatch 함수가 액션을 reducer에게 전달하면 그에 따라 state가 변경되도록 합니다.
컴포넌트의 최상위 레벨에서 useReducer을 호출합니다
const [state, dispatch] = useReducer(reducer, initialState);
useReducer 훅은 두 개의 인자를 받습니다
reduder, initialState (초기상태값)
그리고 두 개의 값을 반환합니다
state, dispatch
useContext
useContext는 리액트에서 상태(state) 관리를 쉽게 하기 위해 사용하는 훅 중 하나입니다.
주로 여러 컴포넌트에서 공통으로 사용하는 데이터를 효율적으로 관리하기 위해 사용됩니다.
왜 useContext를 사용할까?
컴포넌트 트리에서 데이터를 전달하려면 보통 props를 통해 전달합니다.
하지만 트리의 깊이가 깊어지면 props를 계속 전달해야 해서 코드가 복잡해지고 관리하기 어려워집니다 >> 이걸 props drilling이라고 합니다.
useContext를 사용하면 이러한 prop drilling 문제를 해결할 수 있습니다.
최상위 컴포넌트에서 데이터를 제공하고 , 하위 컴포넌트 어디서든 그 데이터를 쉽게 접근할 수 있게 해줍니다.
useContexts는 컴포넌트의 최상위 레벨에서 호출하여 context를 읽고 구독합니다
( 여기서 "구독" 이란 특정 데이터의 변화를 감지하고, 그 변화에 따라 컴포넌트를 업데이트 하는 것을 말합니다 쉽게 말하면 상태가 변경 될 때 마다 컴포넌트가 다시 렌더링 되는 것 )
context > 데이터를 여러 컴포넌트들 사이에서 쉽게 공유할 수 있게 해주는 도구입니다. context 자체는 정보를 보유하지 않으며, 컴포넌트에서 제공하거나 읽을 수 있는 정보의 종류를 나타냅니다.
>> 로그인한 사용자 정보나 테마 설정 같은 것을 여러 컴포넌트에서 사용해야 할 때 유용합니다.
provider > 데이터를 공급해주는 역할을 합니다. provider가 있어야 그 아래에 있는 모든 컴포넌트들이 그 데이터를 사용할 수 있습니다.
useContext: context로부터 데이터를 쉽게 가져올 수 있게 하는 함수로 호출하는 컴포넌트에 대한 context값을 반환합니다.
쉽게 설명해보자면
Context를 큰 상자라고 생각하고, 이 상자 안에는 모든 컴포넌트들이 필요로 하는 정보가 들어있다고 봅시다.
provider는 이 상자를 배달해주는 사람입니다. provider가 상자를 배달하고 그 상자를 받은 모든 사람들(컴포넌트)은 상자에 든 정보를 꺼내서 쓸 수 있습니다.
useContext는 상자를 열고 그 안의 정보를 꺼내는 열쇠입니다.
간단하게 버튼을 누르면 테마 색이 변하는 예제를 살펴보겠습니다.
import { useContext } from 'react';
function Button() {
const theme = useContext(ThemeContext);
useContext는 ThemeContext에 대한 theme 값을 반환한다. theme 값을 반환하기 위해 리액트는 특정 context(theme)에 대해 위에서 가장 가까운 context provider을 찾습니다.
export default function MyApp() {
return (
<ThemeContext.Provider value="dark">
<Form />
</ThemeContext.Provider>
)
}
function Form() {
return (
<Panel title="Welcome">
<Button>Sign up</Button>
<Button>Log in</Button>
</Panel>
);
}
context(theme 값)를 button에 전달하려면 해당 버튼 또는 상위 컴포넌트 중 하나를 해당 context provider 로 감쌉니다
Form 내부의 button 이 useContext(Themecontext)를 호출하면 "dark" 를 값으로 받습니다.
<Context.Provider>는 반드시 useContext() 호출을 수행하는 컴포넌트의 위에 있어야 합니다.
리액트는 변경된 value를 받는 provider부터 시작해서 해당 context를 사용하는 자식들까지 전부 자동으로 리렌더링 합니다.
context를 업데이트 하려면 state와 결합해야 합니다.
부모 컴포넌트에 state 변수를 선언하고 현재 state를 context 값으로 provider에 전달합니다
function MyPage() {
const [theme, setTheme] = useState('dark');
return (
<ThemeContext.Provider value={theme}>
<Form />
<Button onClick={() => {
setTheme('light');
}}>
Switch to light theme
</Button>
</ThemeContext.Provider>
);
}
provider 내보의 모든 Button 은 현재 theme 값을 받게 됩니다. provider에게 전달한 theme 값을 업데이트 하기 위해 setTheme을 호출하면 모든 Button 컴포넌트가 새로운 light 값으로 리렌더링 됩니다.
useRef란?
React에서 제공하는 훅으로, DOM요소나 컴포넌트의 인스턴스를 직접 참조할 수 있게 해줍니다
이러한 상황에서 유용하다!!
- DOM요소에 접근 : 'useRef' 를 사용하여 특정 DOM요소에 접근하고 그 요소의 속성을 직접 변경할 수 있습니다
- 값 저장: 렌더링 간에 값에 저장하고 싶을 때 사용된다. 이 값은 컴포넌트가 리렌더링 되더라도 유지됩니다
- 포커스 제어 : 폼 요소의 포커스를 설정하거나, 다른 이벤트를 제어할 때 유용합니다
컴포넌트의 최상위 레벨에서 useRef를 호출하여 ref를 선언합니다
import { useRef } from 'react';
function MyComponent() {
const intervalRef = useRef(0);
const inputRef = useRef(null);
useRef를 사용할 때 초기값을 설정할 수 있는데, 이 초기값은 current라는 프로퍼티에 저장된다. 이 초기값은 어떤 유형의 값이든 될 수 있습니다
- useRef를 처음 사용할 때 설정하는 초기값은 useRef가 처음 생성될 때만 사용됩니다
- 한 번 설정된 후에는 컴포넌트가 다시 렌더링되더라도 이 초기값은 무시된다. 즉, 초기값은 useRef가 처음 초기화 될 때만 중요합니다
- 이후에는 current 프로퍼티를 통해 값을 변경하거나 접근할 수 있습니다
useRef를 사용하면 current 라는 단일 프로퍼티를 가진 객체를 반환합니다. 이 객체의 current 프로퍼티는 특정 값을 저장하는데 사용됩니다
주요 point❗️
- 값 변경 가능 : 나중에 current 프로퍼티의 값을 다른 값으로 변경할 수 있습니다
- JSX 노드의 ref 속성 : 이 객체를 JSX노드의 ref 속성에 전달하면, React가 자동으로 해당 DOM 요소를 current 프로퍼티에 설정합니다
- 동일한 객체 유지 : 컴포넌트가 다시 렌더링될 때도 useRef는 동일한 객체를 반환합니다
주의사항
ref.current 프로퍼티
- 변이 가능 : ref.current 는 값을 자유롭게 변경할 수 있습니다. 이는 useState와는 다르게 변경될 때 마다 컴포넌트를 다시 렌더링 하지 않습니다
- React 인지 불가 : ref.current 가 변경되더라도 React는 이를 알지 못한다. 따라서 변경 시 컴포넌트가 다시 렌더링 되지 않습니다
상태 관리와의 차이점
- State : 상태를 변경하면 React가 이를 감지하고 컴포넌트를 다시 렌더링 합니다
- Ref : ref.current 는 그냥 객체 속성이기 때문에 변경되어도 React가이를 감지하지 않습니다
주의할 점
- 렌더링 중 사용 금지 : 렌더링 중에는 ref.current를 읽거나 쓰지 않는 것이 좋습니다. 이는 컴포넌트의 동작을 예측할 수 없게 만들 수 있습니다.
- Strict Mode : 개발모드에서는 React는 컴포넌트의 불순물을 찾기위해 함수를 두 번 호출합니다. 이때 각 ref 객체도 두 번 생성되지만 하나는 버려진다. 컴포넌트 함수가 순수하다면 ( 부작용이 없다면 ) 문제되지 않습니다.
여기서 부작용이란 > 함수가 외부 상태를 변경하거나, 함수 호출 시점에 따라 다르게 동작하는 것을 의미합니다.
순수함수 > 호출될 때 마다 동일한 입력에 대해 동일한 출력을 반환하고, 외부 상태를 변경하지 않습니다.
'React 공식문서 스터디' 카테고리의 다른 글
useEffect (2) (1) | 2024.06.05 |
---|---|
useEffect (0) | 2024.06.04 |
useRef (2) (0) | 2024.05.30 |
useRef (0) | 2024.05.29 |
useContext(2) (0) | 2024.05.28 |