[React] useReducer

0

React

목록 보기
2/6

useReducer

useReducer는 컴포넌트에 리듀서(reducer)를 추가할 수 있는 React Hook입니다.

const [state, dispatch] = useReducer(reducer, initialArg, init?)

Reference

useReducer(reducer, initialArg, init?)

리듀서와 함께 컴포넌트의 상태를 관리하려면 컴포넌트의 최상위 수준에서 useReducer를 호출하세요.

import { useReducer } from 'react';

function reducer(state, action) {
  // ...
}

function MyComponent() {
  const [state, dispatch] = useReducer(reducer, { age: 42 });
  // ...

Parameters

  • reducer: 상태가 업데이트되는 방법을 지정하는 리듀서 함수입니다. 순수해야 하며, state와 action을 인수로 받고, 다음 상태를 반환해야 합니다. 상태와 액션은 어떤 유형이든 될 수 있습니다.
  • initialArg: 초기 상태를 계산하는 데 사용되는 값입니다. 어떻게 초기 상태가 계산되는지는 다음 init 인수에 따라 달라집니다.
  • optional init: 초기 상태를 반환해야 하는 초기화 함수입니다. 지정하지 않으면 초기 상태는 initialArg로 설정됩니다. 그렇지 않으면 init(initialArg)의 결과로 초기 상태가 설정됩니다.

Returns

useReducer는 정확히 두 개의 값을 가진 배열을 반환합니다.

  1. 현재 상태입니다. 첫 번째 렌더링에서는 init(initialArg)또는 initialArg(만약 init이 없는 경우)로 설정됩니다.
  2. 상태를 다른 값으로 업데이트하고 다시 렌더링을 트리거하는 디스패치(dispatch) 함수입니다.

Caveats

  • useReducer는 Hook이므로 컴포넌트나 사용자 정의 Hook의 최상위 수준에서만 호출할 수 있습니다. 루프나 조건문 안에서 호출할 수 없습니다. 이를 필요로 하는 경우 새로운 컴포넌트를 추출하고 상태를 해당 컴포넌트로 이동시키세요.
  • Strict 모드에서는 React가 의도하지 않은 불순물(impurities)을 찾기 위해 리듀서와 이니셜라이저를 두 번 호출합니다. 이는 개발 중에만 발생하며 프로덕션에는 영향을 미치지 않습니다. 리듀서와 이니셜라이저가 순수한 경우(그렇게 되어야 합니다), 이는 로직에 영향을 미치지 않습니다. 호출 중 하나의 결과는 무시됩니다.

dispatch function

useReducer로부터 반환된 디스패치(dispatch) 함수를 사용하면 상태를 다른 값으로 업데이트하고 다시 렌더링을 트리거할 수 있습니다. 디스패치 함수에 유일한 인수로 액션을 전달해야 합니다.

const [state, dispatch] = useReducer(reducer, { age: 42 });

function handleClick() {
  dispatch({ type: 'incremented_age' });
  // ...

React는 현재 상태와 dispatch 함수에 전달한 액션을 사용하여 제공된 리듀서 함수를 호출한 결과를 다음 상태로 설정합니다.

Parameters

  • action: 사용자가 수행한 액션입니다. 어떤 유형의 값이든 될 수 있습니다. 일반적으로 액션은 식별하는 type 속성과 선택적으로 추가 정보가 포함된 객체입니다.

Returns

디스패치(dispatch) 함수는 반환값이 없습니다.

Caveats

  • 디스패치(dispatch) 함수는 다음 렌더링을 위해 상태 변수를 업데이트합니다. 디스패치 함수를 호출한 후 상태 변수를 읽으면 호출 이전에 화면에 표시된 이전 값을 가져옵니다.
  • 만약 새로 제공하는 값이 Object.is 비교에 따라 현재 상태와 동일하다면, React는 컴포넌트와 그 자식들을 다시 렌더링하지 않습니다. 이것은 최적화입니다. React는 결과를 무시하기 전에 여전히 컴포넌트를 호출해야 할 수 있지만 코드에 영향을 주지 않아야 합니다.
  • React는 상태 업데이트를 일괄 처리합니다. 모든 이벤트 핸들러가 실행되고 해당 set 함수를 호출한 후 화면을 업데이트합니다. 이렇게 함으로써 단일 이벤트 동안 여러 번 다시 렌더링되는 것을 방지합니다. DOM에 액세스하는 등 React를 이전에 화면을 업데이트하도록 강제해야 하는 드문 경우에는 flushSync를 사용할 수 있습니다.

Usage

Adding a reducer to a component

리듀서를 사용하여 상태를 관리하려면 컴포넌트의 최상위 수준에서 useReducer를 호출하십시오.

import { useReducer } from 'react';

function reducer(state, action) {
  // ...
}

function MyComponent() {
  const [state, dispatch] = useReducer(reducer, { age: 42 });
  // ...

useReducer는 정확히 두 개의 항목이 포함된 배열을 반환합니다.

  1. 이 상태 변수의 현재 상태. 처음에는 제공한 초기 상태로 설정됩니다.
  2. 상호 작용에 대한 응답으로 상태 변수를 변경할 수 있는 디스패치 함수.

화면에 업데이트하려면, 사용자가 수행한 것을 나타내는 객체인 액션을 사용하여 디스패치를 호출하십시오.

function handleClick() {
  dispatch({ type: 'incremented_age' });
}

React는 현재 상태와 액션을 리듀서 함수에 전달합니다. 리듀서 함수는 다음 상태를 계산하고 반환합니다. React는 다음 상태를 저장하고 해당 상태로 컴포넌트를 렌더링하고 UI를 업데이트합니다.

useReducer는 useState와 매우 유사하지만, 이벤트 핸들러에서 상태 업데이트 논리를 하나의 함수로 이동할 수 있습니다. useState와 useReducer 중 어떤 것을 선택해야 할지에 대해 더 자세히 알아보세요.


Writing the reducer function

리듀서 함수는 다음과 같이 선언됩니다.

function reducer(state, action) {
  // ...
}

그런 다음, 다음 상태를 계산하고 반환할 코드를 작성해야 합니다. 관례적으로 switch 문으로 작성하는 것이 일반적입니다. switch의 각 case에서 다음 상태를 계산하고 반환합니다.

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);
}

액션은 어떤 형태든 가질 수 있습니다. 보통은 액션을 식별하는 type 속성을 가진 객체를 전달하는 것이 관례입니다. 이 객체는 reducer가 다음 상태를 계산하는 데 필요한 최소한의 정보를 포함해야 합니다.

function Form() {
  const [state, dispatch] = useReducer(reducer, { name: 'Taylor', age: 42 });
  
  function handleButtonClick() {
    dispatch({ type: 'incremented_age' });
  }

  function handleInputChange(e) {
    dispatch({
      type: 'changed_name',
      nextName: e.target.value
    });
  }
  // ...

액션 타입 이름은 컴포넌트 내부에서만 사용되며, 각각의 액션은 단일 상호작용을 설명하며, 이로 인해 데이터의 여러 변경 사항이 발생할 수 있습니다. 상태의 모양은 임의적이지만 일반적으로 객체나 배열로 표현됩니다.

Avoiding recreating the initial state

React는 초기 상태를 한 번 저장하고 다음 렌더링에서는 무시합니다.

function createInitialState(username) {
  // ...
}

function TodoList({ username }) {
  const [state, dispatch] = useReducer(reducer, createInitialState(username));
  // ...

createInitialState(username) 함수는 초기 렌더링에만 사용되지만, 여전히 모든 렌더링에서 이 함수를 호출합니다. 이는 큰 배열을 생성하거나 비용이 많이 드는 계산을 수행하는 경우 비효율적일 수 있습니다.

이를 해결하기 위해, 세 번째 인자로 useReducer에 초기화 함수로 전달할 수 있습니다.

function createInitialState(username) {
  // ...
}

function TodoList({ username }) {
  const [state, dispatch] = useReducer(reducer, username, createInitialState);
  // ...

위 예시에서 createInitialState 함수는 username 인자를 받는 함수입니다. 만약 초기 상태를 계산하기 위해 정보가 필요하지 않은 경우에는 useReducer에 두 번째 인자로 null을 전달할 수 있습니다. 이렇게 하면 초기 상태가 계산될 때 추가적인 정보를 제공하지 않아도 됩니다.

출처: https://react.dev/reference/react/useReducer

profile
지치지 않는 백엔드 개발자 김성주입니다 :)

0개의 댓글