React 내부적으로 state를 관리할 수 있도록 도움
props 체인을 구축하지 않고도, 앱의 어떤 컴포넌트에서라도 직접 변경하여 직접 전달할 수 있게 해준다.
리액트에 내장된 State 저장소인 React Context를 사용하면 긴 props 체인 만들지 않고도 컴포넌트 전체 state에 관해서 액션을 트리거할 수 있다.
context를 사용하면 중간에 있는 엘리먼트들에게 props를 넘겨주지 않아도 된다.
전역적으로 사용되는 값을 관리할 수 있다. (함수, 상태, 라이브러리 인스턴스 등)
Redux는 '상태(state)'를 관리,
/ Context API는 React 컴포넌트들끼리 props로 정보를 주고 받지 않고 전역적으로 데이터를 가져다 쓸 수 있게 만든 툴
const MyStore = React.createContext(defaultValue);
// 예제
// ./src/store/auth-context.js
const AuthContext = React.createContext({
  isLoggdIn: false,
});
export default AuthContext;
// ./src/App.js
  const [isLoggedIn, setIsLoggedIn] = useState(false);
  return (
      <AuthContext.Provider>
        <MainHeader isAuthenticated={isLoggedIn} onLogout={logoutHandler} />
        <main>
          {!isLoggedIn && <Login onLogin={loginHandler} />}
          {isLoggedIn && <Home onLogout={logoutHandler} />}
        </main>
      </AuthContext.Provider>
  );
/* 2-1. 사용 예제
./src/componenets/Header/Navigation.js */
const Navigation = (props) => {
  return (
    <AuthContext.Consumer>
      {(ctx) => {
        return (
          <nav className={classes.nav}>
            <ul>
              {ctx.isLoggedIn && (
                <li>
                  <a href="/">Users</a>
                </li>
              )}
              {props.isLoggedIn && (
                <li>
                  <a href="/">Admin</a>
                </li>
              )}
              {props.isLoggedIn && (
                <li>
                  <button onClick={props.onLogout}>Logout</button>
                </li>
              )}
            </ul>
          </nav>
        );
      }}
    </AuthContext.Consumer>
  );
};
Context.Consumer로 감싸준다.{ isLoggdIn: false, } 가 된다.🧐 근데 저장하면 TypeError가 뜬다. 왜?
왜냐면 React.createContext에 기본값이 있지만, 이는 실제로 공급자 없이 소비하는 경우에만 사용되기 때문이다. 따라서 공급자는 필요하지 않음. 
🧐 근데 공급자가 필요하다고 했잖아?
정확히 말하면 기본값이 있으면 공급자는 필요 없다.
그러나 실제론 변할 수 있는 값을 갖기 위해 공급자를 사용할 것이다.
따라서 충돌이 일어나지 않기 위해선 공급자 컴포넌트에서 프롭 값을 주자.
// ./src/App.js
  return (
    <AuthContext.Provider value={{ isLoggdIn: false }}>
      <MainHeader isAuthenticated={isLoggedIn} onLogout={logoutHandler} />
      <main>
        {!isLoggedIn && <Login onLogin={loginHandler} />}
        {isLoggedIn && <Home onLogout={logoutHandler} />}
      </main>
    </AuthContext.Provider>
  );
value라는 이름을 가져야한다.이제 문제없이 로드된다.
근데 링크가 누락됨
→ 왜냐면 ctx.isLoggdIn에서 데이터를 가져오기 때문.
// ./src/App.js
  return (
    <AuthContext.Provider 
    value={{ isLoggedIn: isLoggedIn }}> 
    // false에서 isLoggdIn으로 변경 
    
      <MainHeader isAuthenticated={isLoggedIn} onLogout={logoutHandler} />
      <main>
        {!isLoggedIn && <Login onLogin={loginHandler} />}
        {isLoggedIn && <Home onLogout={logoutHandler} />}
      </main>
    </AuthContext.Provider>
  );
isLoggedIn 값을 하드코딩하는 대신, isLoggedIn 변경한다.value 객체는 isLoggedIn 변경될 때마다 리액트에 의해 업데이트 된다.그래서 isAuthenticated의 props 제거할 수 있다.
// ./src/App.js
  return (
    <AuthContext.Provider value={{ isLoggedIn: isLoggedIn }}>
      <MainHeader onLogout={logoutHandler} />
      <main>
        {!isLoggedIn && <Login onLogin={loginHandler} />}
        {isLoggedIn && <Home onLogout={logoutHandler} />}
      </main>
    </AuthContext.Provider>
  );
그리고 MainHeader에선 Navigation으로의 전달을 중단한다.
const MainHeader = (props) => {
  return (
    <header className={classes['main-header']}>
      <h1>A Typical Page</h1>
      <Navigation 
// isLoggedIn={props.isAuthenticated} 
onLogout={props.onLogout} />
    </header>
  );
};
이제 Navigation에서 context.isLoggedIn을 사용할 수 있다.
모든 props를 ctx로 바꿔주자. 
// ./src/componenets/Header/Navigation.js 
const Navigation = () => {
  return (
    <AuthContext.Consumer>
      {(ctx) => {
        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={ctx.onLogout}>Logout</button>
                </li>
              )}
            </ul>
          </nav>
        );
      }}
    </AuthContext.Consumer>
  );
};
다시 링크도 돌아왔다.
근데 함수에서 코드를 반환({(ctx) => { return (....)}}) 하는 건 별로라서 useContext hook을
사용하는 게 낫다.
// ./src/componenets/Header/Navigation.js 
import { useContext } from 'react'; // 추가
const Navigation = (props) => {
  const ctx = useContext(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={ctx.onLogout}>Logout</button>
          </li>
        )}
      </ul>
    </nav>
  );
};
이렇게 하면 Context 값을 얻을 수 있다.
// ./src/store/auth-context.js
const AuthContext = React.createContext({
  isLoggdIn: false,
  onLogout: () => {}
});
export default AuthContext;
// ./src/store/auth-context.js
const AuthContext = React.createContext({
  isLoggdIn: false,
  onLogout: () => {}
});
// 추가 
export const AuthContextProvider = (props) => {
  return <AuthContext.Provider>{props.children}</AuthContext.Provider>;
};
export default AuthContext;
AuthContextProvider 컴포넌트를 추가해 props 받아와서 들어오는 모든 것을 전달하면 된다.
이렇게 하면 이제 useState를 임포트 할 수 있다. 
// ./src/store/auth-context.js
import React, { useState } from "react";
const AuthContext = React.createContext({
  isLoggdIn: false,
  onLogout: () => {},
});
export const AuthContextProvider = (props) => {
  const [isLoggdIn, setIsLoggedIn] = useState(false);
  const logoutHandler = () => {
    setIsLoggedIn(false);
  };
  const loginHandler = () => {
    setIsLoggedIn(true);
  };
  return (
    <AuthContext.Provider
      value={{
        isLoggdIn: isLoggdIn,
        onLogout: logoutHandler,
      onLogin: (email, password) => {},
      }}
    >
      {props.children}
    </AuthContext.Provider>
  );
};
AuthContextProvider 컴포넌트에서 전체 로그인 State를 관리하여 모든 컨텍스트를 설정했다. === App 컴포넌트 간결// ./src/App.js
function App() {
  const ctx = useContext(AuthContext);
  return (
    <React.Fragment>
      <MainHeader />
      <main>
        {!ctx.isLoggdIn && <Login />}
        {ctx.isLoggdIn && <Home />}
      </main>
    </React.Fragment>
  );
}
// ./src/store/auth-context.js
import React, { useState, useEffect } from "react";
const AuthContext = React.createContext({
  isLoggdIn: false,
  onLogout: () => {},
  onLogin: (email, password) => {},
});
export const AuthContextProvider = (props) => {
  const [isLoggdIn, setIsLoggedIn] = useState(false);
  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={{
        isLoggdIn: isLoggdIn,
        onLogout: logoutHandler,
        onLogin: loginHandler,
      }}
    >
      {props.children}
    </AuthContext.Provider>
  );
};
export default AuthContext;