728x90
반응형

우리가 현재 만들고 있는 프로젝트를 보면, App 컴포넌트에서 onToggle, onRemove 가 구현이 되어있고 이 함수들은 UserList 컴포넌트를 거쳐서 각 User 컴포넌트들에게 전달이 되고 있다.

 

컴포넌트들이 상위 컴포넌트에서 하위컴포넌트로 전달되어지는 방법이다.

 

상위컴포넌트에서 함수들이 전달되어질 때, 거쳐야 할 컴포넌트가 여러개 ( 즉 하위 컴포넌트의 하위 컴포넌트의 ... )가

되면 매우 번거로운 작업이 될 것이다.

 

이 때 리액트의 Context API 와 이전 섹션에서 배웠던 dispatch 를 함께 사용하면 이러한 복잡한 구조를 해결 할 수 있다.

 

먼저 이렇게 React.createContext() 라는 함수를 사용한다.

const UserDispatch = React.createContext(null);

 

 

이러면 Context의 기본 값을 설정해줄 수 있다. 위에서 설정한 값은 따로 값을 사용하지 않았을 때의 기본 값이다.

 

Context를 만들면 Context안에 Provider 라는 컴포넌트가 들어있는데, 이 컴포넌트를 통해 Context의 값을 지정해줄 수

있다. value라는 값을 설정해주면 된다.

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

 

아래 전체 코드를 보면서 이해해보자.

 

App.js

import React, { useRef, useReducer, useMemo, useCallback } from 'react';
import UserList from './UserList';
import CreateUser from './CreateUser';
import useInputs from './hooks/useInputs';

function countActiveUsers(users) {
  console.log('활성 사용자 수를 세는중...');
  return users.filter(user => user.active).length;
}

const initialState = {
  users: [
    {
      id: 1,
      username: 'velopert',
      email: 'public.velopert@gmail.com',
      active: true
    },
    {
      id: 2,
      username: 'tester',
      email: 'tester@example.com',
      active: false
    },
    {
      id: 3,
      username: 'liz',
      email: 'liz@example.com',
      active: false
    }
  ]
};

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

// UserDispatch 라는 이름으로 내보내줍니다.
export const UserDispatch = React.createContext(null);

function App() {
  const [{ username, email }, onChange, onReset] = useInputs({
    username: '',
    email: ''
  });
  const [state, dispatch] = useReducer(reducer, initialState);
  const nextId = useRef(4);

  const { users } = state;

  const onCreate = useCallback(() => {
    dispatch({
      type: 'CREATE_USER',
      user: {
        id: nextId.current,
        username,
        email
      }
    });
    onReset();
    nextId.current += 1;
  }, [username, email, onReset]);

  const onToggle = useCallback(id => {
    dispatch({
      type: 'TOGGLE_USER',
      id
    });
  }, []);

  const onRemove = useCallback(id => {
    dispatch({
      type: 'REMOVE_USER',
      id
    });
  }, []);

  const count = useMemo(() => countActiveUsers(users), [users]);
  return (
    <UserDispatch.Provider value={dispatch}>
      <CreateUser
        username={username}
        email={email}
        onChange={onChange}
        onCreate={onCreate}
      />
      <UserList users={users} onToggle={onToggle} onRemove={onRemove} />
      <div>활성사용자 수 : {count}</div>
    </UserDispatch.Provider>
  );
}

export default App;

 

 

위에서 말했듯이 React.createContext 함수로 내보냈고,

 

    <UserDispatch.Provider value={dispatch}>
      <CreateUser
        username={username}
        email={email}
        onChange={onChange}
        onCreate={onCreate}
      />
      <UserList users={users} onToggle={onToggle} onRemove={onRemove} />
      <div>활성사용자 수 : {count}</div>
    </UserDispatch.Provider>

이런 식으로 컴포넌트들을 .Provider에 감싸고, value로 Context의 값을 지정해주었다.

 

 

그 다음 감싼 컴포넌트 내에서 먼저 import를 해주고,

import { UserDispatch } from './App';

 

 

아래와 같이 useContext를 사용하여 불러왔던 UserDispatch를 사용하게끔 설정해주면 끝!!

const User = React.memo(function User({ user }) {
  const dispatch = useContext(UserDispatch);

 

 

이제 우리는 여러 컴포넌트를 거쳐서 전달할 필요없이 최상위 폴더에서 React.createContext 함수를 써서 내보내고,

Provider로 하위 컴포넌트를 감싼다음에 사용할 필요가 있을 때 useContext로 편하게 불러올 수 있다!

 

 

참고로 React.createContext를 안쓰고

import React, { useReducer, createContext } from 'react';

이런식으로 불러와도 된다.

 

 

참조 

http://react.vlpt.us/basic/22-context-dispatch.html

728x90
반응형

'Front-End > React.js' 카테고리의 다른 글

React.js | 입문 | Immer  (0) 2021.09.17
React.js | 입문 | Context API 전역 값 관리(2)  (0) 2021.09.17
React.js | 입문 | React.memo  (0) 2021.09.17
React.js | 입문 | useCallback  (0) 2021.09.17
React.js | 입문 | 커스텀 Hook  (0) 2021.09.17

+ Recent posts