Context API로 전역 값 관리하기

Doum Kim·2020년 5월 15일
0

React - 기초

목록 보기
18/20
post-thumbnail

우리가 지금까지 만든 프로젝트에서는 App 컴포넌트에서 모든 기능을 구현하고 props로 자식 컴포넌트에 전달하는 방식으로 값을 관리하였다. 그런데 어떤 컴포넌트에서는 사용은 하지 않지만 props로 전달하기 위한 징검다리 역할만 하는 컴포넌트들이 있다.

우리가 진행했던 프로젝트에서는 컴포넌트의 수가 적어서 불편함을 느끼지 못 할 수가 있다. 하지만 여러개의 컴포넌트에 내부에 있는 컴포넌트라면 계속해서 props를 내려줘야하는 불편함이 있다.

컴포넌트1 → 컴포넌트2 → 컴포넌트3 → 컴포넌트4 → ... → 컴포넌트 n

이러한 문제점을 해결하기 위해서 Context API와 dispatch를 이용하면 값을 전역으로 관리하여 props로 일일이 내려줘야하는 번거로움을 줄일 수 있다.

Context API 사용법

Context 생성

const UserDispatch = React.createContext('context의 기본 값');

따로 값을 지정하지 않을 경우에는 createContext에 null 값을 넣어주면 된다.
Context를 생성하면 Provider라는 컴포넌트가 Context안에 들어있다. Provider 컴포넌트에 value라는 값을 설정하여 Context의 값을 설정해 줄 수 있다.

<UserDispatch.Provider value={dispatch}>... </UserDispatch.Provider>

이렇게 설정을 하면 Provider 컴포넌트에 감싸져있는 컴포넌트 어디서든 Context의 값을 사용할 수 있다. 실제 코드에 적용을 해보면 다음과 같다.

import React, { useMemo, useReducer, createContext } from 'react';
import UserList from './UserList';
import CreateUser from './CreateUser';

const countActiveUsers = (users) => {
  console.log('카운트');
  return users.filter((user) => user.active).length;
};

const initialState = {
  users: [
    {
      id: 1,
      username: 'Kim',
      age: 20,
      active: false,
    },
    {
      id: 2,
      username: 'Lee',
      age: '30',
      active: false,
    },
    {
      id: 3,
      username: 'Choi',
      age: '50',
      active: false,
    },
  ],
  inputs: {
    username: '',
    age: '',
  },
};

const reducer = (state, action) => {
  switch (action.type) {
    case 'CREATE_USER':
      return {
        inputs: initialState.inputs,
        users: [...state.users, action.user],
      };
    case 'REMOVE_USER':
      return {
        ...state,
        users: state.users.filter((user) => {
          return user.id !== action.id;
        }),
      };
    case 'TOGGLE_USER':
      return {
        ...state,
        users: state.users.map((user) => {
          return user.id === action.id
            ? { ...user, active: !user.active }
          : user;
        }),
      };
    default:
      return state;
  }
};

//UserDispatch Context 생성
export const UserDispatch = createContext(null);

export default function App() {
  const [state, dispatch] = useReducer(reducer, initialState);

  const { users } = state;

  const count = useMemo(() => countActiveUsers(users), [users]);

  return (
    // provider로 감싸고 내부 컴포넌트에서 context 값 사용
    <UserDispatch.Provider value={dispatch}>
      <CreateUser />
      <div>activeUser : {count}</div>
      <UserList users={users} />
    </UserDispatch.Provider>
  );
}

이렇게 export한 context를 값을 사용할 컴포넌트에서 불러와서 useContext라는 hook을 사용해서 context를 사용할 수 있다.

Context 사용하기

UserList.jsx

import React, { useContext } from 'react';
import { UserDispatch } from './App';

const User = React.memo(({ user }) => {
  const dispatch = useContext(UserDispatch);
  const { active, age, username, id } = user;
  return (
    <>
      <div>
        <span
          style={{
            cursor: 'pointer',
              color: active ? 'red' : '#000',
          }}
          onClick={() => dispatch({ type: 'TOGGLE_USER', id })}
          >
          username: {username}, age: {age}
        </span>
        <button
          onClick={() => {
            dispatch({
              type: 'REMOVE_USER',
              id,
            });
          }}
          >
          삭제
        </button>
      </div>
      </>
  );
});

const UserList = ({ users }) => {
  console.log('UserList 렌더링');
  return (
    <>
      {users.map((user) => {
        return <User user={user} key={user.id} />;
      })}
      </>
  );
};

export default React.memo(UserList);

CreateUser.jsx

import React, { useContext, useRef } from 'react';
import useInput from './useInput';
import { UserDispatch } from './App';

const CreateUser = () => {
  console.log('createUser 렌더링');
  const [{ username, age }, onChange, reset] = useInput({
    username: '',
    age: '',
  });
  const nextId = useRef(4);
  const dispatch = useContext(UserDispatch);
  const onCreate = () => {
    dispatch({
      type: 'CREATE_USER',
      user: {
        username,
        age,
        id: nextId.current,
      },
    });
    reset();
    nextId.current += 1;
  };
  return (
    <>
      <input onChange={onChange} value={username} name="username" type="text" />
      <input onChange={onChange} value={age} name="age" type="number" />
      <button onClick={onCreate}>추가</button>
      </>
  );
};

export default React.memo(CreateUser);

0개의 댓글