useReducer(reducer, initialArg, init?)
useReducer는 컴포넌트에 reducer를 추가할 수 있는 React입니다.
const [state, dispatch] = useReducer(reducer, initialArg, init?)
컴포넌트의 최상위 레벨에서 useReducer를 호출하여 reducer를 통해 state를 관리 할 수 있다.
import { useReducer } from 'react';
function reducer(state, action) {
// ...
}
function MyComponent() {
const [state, dispatch] = useReducer(reducer, { age: 42 });
// ...
매개변수( Parameters )
- reducer : state가 업데이트되는 방식을 지정하는 reducer 함수이다. 순수 함수여야 하고 state와 액션을 인자로 받아야 하며, 다음 state를 반환해야 한다. state와 액션은 어떤 유형이든 가능하다.
- initialArg : 초기 state가 계산되는 값으로 모든 유형이 가능하다. 이 값에서 초기 state를 계산하는 방법은 다음 init 인자에 따라 달라진다.
- 선택적(optional) init : 초기 state 계산 방법을 지정하는 초기화 함수다. 미리 지정하지 않으면 초기 state는 initialArg로 설정되고 그렇지 않으면 초기 state는 init(initialArg)를 호출한 결과로 설정된다.
반환값( Returns )
- 현재 state. 첫번째 렌더링 중에는 init(initialArg) 또는 (init이 없는 경우) initialArg로 설정된다.
- state를 다른 값으로 업데이트하고 리렌더링을 촉발할 수 있는 dispatch function.
주의사항( Caveats )
- useReducer는 훅이므로 컴포넌트의 최상위 레벨 또는 자체 훅에서만 호출할 수 있다. 반복문이나 조건문 내부에서는 호출 할 수 없다. 필요하다면 새 컴포넌트를 추출하고 state를 그 안에 옮겨야 한다.
- Strict Mode에서 React는 의도치 않은 불순물을 찾기 위해 reducer와 초기화 함수를 두 번 호출한다. 이는 개발 전용 동작이며 상용 환경에서는 영향을 미치지 않는다. reducer와 초기화 함수가 순수하다면(그래야 함) 컴포넌트의 로직에 영향을 미치지 않는다. 호출 중 하나의 결과는 무시된다.
dispatch function
useReducer가 반환하는 dispatch함수를 사용하면 staet를 다른 값으로 업데이트하고 다시 렌더링을 촉발할 수 있다. dispatch함수에 유일한 인수로 액션을 전달해야 한다.
const [state, dispatch] = useReducer(reducer, { age: 42 });
function handleClick() {
dispatch({ type: 'incremented_age' });
// ...
React는 reducer함수에 현재 state와 dispatch한 액션을 전달하고, 그 결과를 다음 state로 설정한다.
매개변수 ( Parameters )
action : 사용자가 수행한 작업이다. 어떤 데이터 유형이든 올 수 있고 관용적으로 액션은 보통 이를 식별하는 type 속성이 있는 객체이며, 선택적으로 추가 정보가 있는 다른 속성을 포함할 수 있다.
반환값( Returns )
dispatch 함수에는 반환값이 없다.
주의사항( Caveats )
- dispatch함수는 다음 렌더링에 대한 state 변수만 업데이트 한다. 만약 dispatch 함수를 호출한 후 state변수를 읽으면 호출 전 화면에 있던 이전 값이 계속 표시된다.
- 만약 여러분 제공한 새 값이 object.is로 비교했을 때 현재 state와 동일하다면, React는 컴포넌트와 그 자식들을 다시 렌더링하는 것을 건너뛴다(최적화). React는 결과를 무시하기 전에 여전히 컴포넌트를 호출하게 될 수도 있지만, 코드에 영향을 미치지는 않는다.
- React는 state업데이트를 일괄 처리한다. 모든 이벤트 핸들러가 실행되고 set 함수를 호출한 후에 화면을 업데이트 한다. 이렇게 하면 단일 이벤트 중에 여러번 다시 렌더링되는 것을 방지할 수 있다. 드물지만 DOM에 접근하기 위해 React가 화면을 더 일찍 업데이트하도록 강제해야 하는 경우, flushSync를 사용할 수 있다.
// flushSync를 사용하여 count 상태를 즉시 업데이트
flushSync(() => {
setCount(count + 1);
});
사용법( Usage )
컴포넌트에 reducer 추가하기
컴포넌트의 최상위 레벨에서 useReducer를 호출하여 reducer로 state를 관리한다.
import { useReducer } from 'react';
function reducer(state, action) {
// ...
}
function MyComponent() {
const [state, dispatch] = useReducer(reducer, { age: 42 });
// ...
useReducer는 정확히 두 개의 항목이 있는 배열을 반환한다.
- 이 state 변수의 현재 state로 처음에 제공한 초기 state로 설정된다.
- 상호작용에 반응하여 이를 변경할 수 있는 dispatch 함수
화면에 표시되는 내용을 업데이트하려면 사용자가 수행한 작업을 나타내는 객체, 즉 액션을 사용하여 dispatch를 호출한다.
function handleClick() {
dispatch({ type: 'incremented_age' });
}
React는 현재 state와 액션을 reducer함수에 전달한다. Reducer는 다음 state를 계산하고 반환한다. React는 다음 state를 저장하고, 컴포넌트를 렌더링하고, UI를 업데이트한다. 아래 예시문 참고!
import { useReducer } from 'react';
function reducer(state, action) {
if (action.type === 'incremented_age') {
return {
age: state.age + 1
};
}
throw Error('Unknown action.');
}
export default function Counter() {
const [state, dispatch] = useReducer(reducer, { age: 42 });
return (
<>
<button onClick={() => {
dispatch({ type: 'incremented_age' })
}}>
Increment age
</button>
<p>Hello! You are {state.age}.</p>
</>
);
}
useReducer는 useState와 매우 유사하지만 이벤트 핸들러의 state 업데이트 로직을 컴포넌트 외부의 단일 함수로 옮길 수 있다. 더 자세한 내용 useState와 useReducer 중 하나를 선택하는 방법에서 확인할 수 있다.
reducer 함수 작성하기
Reducer 함수는 다음과 같이 선언된다.
function reducer(state, action) {
// ...
}
다음 state를 계산하고 반환할 코드를 입력해야 한다. 관례상 switch문으로 작성하는 것이 일반적이다.
swich의 각 case에 대해 다음 state를 계산하고 반환해야 한다.
function reducer(state, action) {
switch (action.type) {
case 'incremented_age': {
return {
name: state.name,
age: state.age + 1
};
}
case 'changed_name': {
return {
name: action.nextName,
age: state.age
};
}
}
throw Error('Unknown action: ' + action.type);
}
액션 유형 이름은 컴포넌트에 로컬로 지정된다. 각 액션은 아무리 많은 데이터를 변경하게 되더라도 오직 하나의 상호작용만을 기술한다. state의 모양은 임의적이지만 일반적으로 객체나 배열이 된다.
state는 읽기 전용으로 state의 객체나 배열을 수정하면 안된다!
function reducer(state, action) {
switch (action.type) {
case 'incremented_age': {
// 🚩 Don't mutate an object in state like this:
state.age = state.age + 1;
return state;
}
대신, reducer로부터 새로운 객체를 반환한다.
function reducer(state, action) {
switch (action.type) {
case 'incremented_age': {
// ✅ Instead, return a new object
return {
...state,
age: state.age + 1
};
}
'React-study > dil' 카테고리의 다른 글
[DIL] useContext (0) | 2024.05.29 |
---|---|
[DIL] useReducer(2) (0) | 2024.05.28 |
[DIL] useState 사용법 (0) | 2024.05.20 |
[DIL] useState(2) (0) | 2024.05.17 |
[DIL] useState(1) (0) | 2024.05.16 |