React의 작동 원리 - useContext

김명성·2022년 5월 14일
0

REACT

목록 보기
30/32
import React from 'react'

// createContext는 기본 컨텍스트를 만든다.
// 여기서의 컨텍스트는 빈 state의 컴포넌트일 뿐이다.
// 이후 이 state가 어떤 모습을 갖추어야 하는지는 개발자의 의도에 달려있다.

// 대부분의 경우에는 객체를 입력한다.
// AuthContext 자체는 컴포넌트가 아니지만, 컴포넌트를 감싸는 객체이다. 
const AuthContext = React.createContext({
  isLoggedIn: false
})

// 다른 컴포넌트,파일에서도 사용할 수 있게 export한다.

// 작성한 Context를 사용하기 위해서는 두가지 작업을 수행해야 한다.

// 1. 공급 : JSX 코드로 감싸는 것을 뜻한다.
// 기본적으로 React에게 Context가 어디있는지 알려준다.
// AuthContext로 감싸인 컴포넌트는, AuthContext를 소비할 수 있는 자격을 얻는다.

// 2. 리스닝: AuthContext에 접근하기 위해서는 두가지 리스닝 방법이 존재한다.
// AuthContext.Consumer 또는 React Hook을 사용하는데, 일반적으로는 React Hook을 사용한다.
//
export default AuthContext

function App() {
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  useEffect(() => {
    const storedUserLoggedInInformation = localStorage.getItem('isLoggedIn');

    if (storedUserLoggedInInformation === '1') {
      setIsLoggedIn(true);
    }
  }, []);

  const loginHandler = (email, password) => {
    // We should of course check email and password
    // But it's just a dummy/ demo anyways
    localStorage.setItem('isLoggedIn', '1');
    setIsLoggedIn(true);
  };

  const logoutHandler = () => {
    localStorage.removeItem('isLoggedIn');
    setIsLoggedIn(false);
  };

  return (
      // AuthContext 자체가 컴포넌트가 되지는 않는다. 하지만 JSX에 호출하려면 컴포넌트가 필요하다.
      // 컴포넌트의 역할은 Provider로 호출한다.
      // AuthContext.Provider로 감싸인 Component는 이제 AuthContext에 작성된 객체에 접근할 수 있다.
      // 그리고 value 프롭스에 전달하려는 객체를 전달한다.
      // value에 전달하는 isLoggedIn 객체가 변경될 때마다, 감싸인 Component에게 변경된 isLoggedIn이 전달된다.
        <AuthContext.Provider value={isLoggedIn}>
      <MainHeader isAuthenticated={isLoggedIn} onLogout={logoutHandler} />
      <main>
        {!isLoggedIn && <Login onLogin={loginHandler} />}
        {isLoggedIn && <Home onLogout={logoutHandler} />}
      </main>
      </AuthContext.Provider>
    
  );
}

export default App;

App component에서 존재하는 state,함수를 props drilling없이 AuthContext.Propvider로 감싸인 컴포넌트에게 전달할수도 있다.

function App() {
  ...
  const [isLoggedIn, setIsLoggedIn] = useState(false);
  
    const logoutHandler = () => {
    localStorage.removeItem('isLoggedIn');
    setIsLoggedIn(false);
  };
  ...
  return(
    ...
        <AuthContext.Provider value={{
          isLoggedIn, // isLoggedIn:isLoggedIn
          onLogout: logoutHandler
        }}>
      )
      ...
// Navigation.js에서는 사용자가 인증되었는지 여부를 확인해야한다.
// 이를 위해서 작성한 AuthContext를 사용할 수 있다.
// useContext는 Context를 사용하게 해주며, 리스닝할 수 있게 한다.
// 사용법은 간단하다. Component 함수에서 useContext를 호출한 뒤
// Context에게 사용하려는 Context를 가리키는 Pointer를 전달하기만 하면 된다.
import React, {useContext} from 'react';
import AuthContext from '../store/auth-context';

import classes from './Navigation.module.css';



const Navigation = (props) => {
  // useContext를 호출하고 상수에 저장한다.
  const ctx = useContext(AuthContext)

  //이제 AuthContext의 객체에 접근할 수 있다.
  return (
    <nav className={classes.nav}>
      <ul>
        {ctx.isLoggedIn && (
          <li>
            <a href="/">Users</a>
          </li>
        )}
        {ctx.isLoggedIn && (
          <li>
            <a href="/">Admin</a>
          </li>
        )}
        {ctx.isLoggedIn && (
          <li>
            <button onClick={props.onLogout}>Logout</button>
          </li>
        )}
      </ul>
    </nav>
  );
};

export default Navigation;

useContext를 사용하여 props는 더이상 Navigation.js에서 사용되지 않는다.

{ctx.isLoggedIn && (
          <li>
            {/* props가 아닌 useContext를 사용하여 ctx.onLogout을 실행.*/}
            <button onClick={ctx.onLogout}>Logout</button>
          </li>
        )}

const AuthContext = React.createContext({
  // dummy 함수와 dummy value를 저장하는 이유는
  // IDE 자동 완성을 더 좋게 만들기 위해서다.
  
  isLoggedIn: false,
  onLogout: () => {},
  onLogIn: (email,password) => {}
})

// 데이터를 관리하는 방법에 따라 다르지만,
// 더 많은 로직을 가져와서 사용해야 하는 경우가 있을 수 있다.
// 이렇게 하는 이유는, 이제 AuthContextProvider 컴포넌트를 통해
// useState를 import 하여
// App.js가 아닌, AuthContextProvider에서 state와 함수를 직접 관리할 수 있기 때문이다.

export const AuthContextProvider = ({children}) => {
  const [isLoggedIn,setIsLoggedIn] = useState();

  useEffect(() => {
    const storedUserLoggedInInformation = localStorage.getItem('isLoggedIn');

    if (storedUserLoggedInInformation === '1') {
      setIsLoggedIn(true);
    }
  }, []);


  const logoutHandler = () => {
    localStorage.removeItem('isLoggedIn');
    setIsLoggedIn(false);
  }

  const loginHandler = () => {
    localStorage.setItem('isLoggedIn', '1');
    setIsLoggedIn(true);
  }

  return <AuthContext.Provider value={{isLoggedIn,onLogin:loginHandler,onLogout:logoutHandler}}>{children}</AuthContext.Provider>
}


export default AuthContext
function App() {
  const ctx = useContext(AuthContext)

  return (
        //App component에서 존재하는 state,함수를
        //props drilling없이 AuthContext.Propvider로 감싸인 컴포넌트에게 전달할수도 있다.
        <>
      <MainHeader onLogout={ctx.logoutHandler} />
      <main>
        {!ctx.isLoggedIn && <Login />}
        {ctx.isLoggedIn && <Home />}
      </main>
      </>
    
  );
}

export default App;

0개의 댓글