본문 바로가기

개발 공부

[리액트 공식 문서] Reducer와 Context로 확장하기

Reducer와 Context

- Reducer를 사용하면 컴포넌트의 state 업데이트 로직을 통합할 수 있다.

- Context를 사용하면 다른 컴포넌트들에 정보를 전달할 수 있다.

reducer와 context를 결합하기

- state와 dispatch 함수를 props를 통해 전달하느 대신 context에 넣어서 사용할 수 있는데, 이점은 prop drilling 없이 TaskBoard 아래의 모든 컴포넌트 트리에서 tasks를 읽고 dispatch 함수를 실행 할 수 있다.

Reducer와 context 결합 방법

1. context를 생성한다.

2. state과 dispatch 함수를 context에 넣는다.

3. 트리 안에서 context를 사용한다.

Step1: Context 생성하기

- 트리를 통해 전달하려면, 두개의 별개의 context를 생성한다.

예)

- TasksContext는 현재 tasks 리스트를 제공한다.

- TasksDispatchContext는 컴포넌트에서 action을 dispatch 하는 함수를 제공한다.

import { createContext } from 'react';

export const TasksContext = createContext(null);
export const TasksDispatchContext = createContext(null);

Step2: State와 dispatch 함수를 context에 넣기

import { TasksContext, TasksDispatchContext } from './TasksContext.js';

export default function TaskApp() {
  const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);
  // ...
  return (
    <TasksContext.Provider value={tasks}>
      <TasksDispatchContext.Provider value={dispatch}>
        ...
      </TasksDispatchContext.Provider>
    </TasksContext.Provider>
  );
}

트리 안에서 context 사용하기

export default function TaskList() {
  const tasks = useContext(TasksContext);
  // ...
  
  export default function AddTask() {
  const [text, setText] = useState('');
  const dispatch = useContext(TasksDispatchContext);
  // ...
  return (
    // ...
    <button onClick={() => {
      setText('');
      dispatch({
        type: 'added',
        id: nextId++,
        text: text,
      });
    }}>Add</button>
    // ...

- TaskBoard 컴포넌트는 자식 컴포넌트에, TaskList는 Task 컴포넌트데 이벤트 핸들러를 전달하지 않는다.

하나의 파일로 합치기

1. Reducer로 state를 관리한다.

2. 두 context를 모두 자식 컴포넌트에 제공한다.

3. children을 prop을 받기 때문에 JSX를 전달할 수 있다.

export function TasksProvider({ children }) {
  const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);

  return (
    <TasksContext.Provider value={tasks}>
      <TasksDispatchContext.Provider value={dispatch}>
        {children}
      </TasksDispatchContext.Provider>
    </TasksContext.Provider>
  );
}

import AddTask from './AddTask.js';
import TaskList from './TaskList.js';
import { TasksProvider } from './TasksContext.js';

export default function TaskApp() {
  return (
    <TasksProvider>
      <h1>Day off in Kyoto</h1>
      <AddTask />
      <TaskList />
    </TasksProvider>
  );
}

- TasksContext.js에서 context를 사용하기 위한 use 함수들도 내보낼 수 있습니다.

export function useTasks() {
  return useContext(TasksContext);
}

export function useTasksDispatch() {
  return useContext(TasksDispatchContext);
}

const tasks = useTasks();
const dispatch = useTasksDispatch();

->  컴포넌트들이 데이터를 어디서 가져오는지가 아닌 무엇을 보여줄 것인지에 집중할 수 있도록 깨끗하게 정리할 수 있다.

 

참고

https://react-ko.dev/learn/scaling-up-with-reducer-and-context