-
React 전역 변수를 사용하자 (부모-자식 컴포넌트 접근, Context)DEV/react 2024. 2. 21. 16:57
React를 사용하면 Component로 화면을 분리하여 사용하게 된다.
물론 Props을 통해 변수나 함수를 던지고 사용할 수 있지만 나처럼 멍청한 사람은 React의 특징을 이해하지도 못한채 router로 페이지를 나눠버리고 그 안에서도 여러 depth의 Component를 구성하게 되는 경우도 있다.
API 통신을 통해 가져온 Token을 전역 변수로 설정하려고 했는데 로그인 페이지와 접속 이후 페이지가 React router로 나눠버리는 바람에 Props로 던지기가 힘들었다.
그래서 전역 변수로 사용하는 법을 찾게 되었고 그 방법에 대해 설명하려고 한다.
1. tkContext.js 생성
index.js의 Router render 부분을 감싸줄 Provider를 만들어야 했다.
나는 토큰을 저장하는 전역 변수를 만들기 위해 tk.Context.js를 생성하고 다음과 같이 작성하였다.
import React, {createContext, useState} from "react"; // Context 생성 const tkContext = createContext(); const TkProvider = ({ children }) => { // token을 관리할 공간 생성 const [token, setToken] = useState(''); return ( <tkContext.Provider value={{ token, setToken }}> {children} </tkContext.Provider> ) } // Context와 Provider export export { tkContext, TkProvider };
2. Index.js 수정
나는 Index.js에서 react router를 통해 페이지를 구성했다.
render를 하고 있던 RouterProvider를 위에 작성한 TkProvider로 감싸주었다.
import React from 'react'; import ReactDOM from 'react-dom/client'; import './index.css'; import reportWebVitals from './reportWebVitals'; import LoginPage from "./view/./page/LoginPage"; import ManagerLoginPage from "./view/./page/ManagerLoginPage"; import ManagementPage from "./view/./page/ManagementPage"; import { createBrowserRouter } from 'react-router-dom'; import { RouterProvider } from "react-router"; import { TkProvider } from "./tkContext"; // Context 불러오기 const root = ReactDOM.createRoot(document.getElementById('root')); const router = createBrowserRouter([ { path: "/", element: <LoginPage />, // errorElement: <ErrorPage />, }, { path: "/manager", element: <ManagerLoginPage />, // errorElement: <ErrorPage />, }, { path: "/management", element: <ManagementPage />, // errorElement: <ErrorPage />, }, ]); root.render( <TkProvider> <RouterProvider router={router} /> </TkProvider> ); // If you want to start measuring performance in your app, pass a function // to log results (for example: reportWebVitals(console.log)) // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals reportWebVitals();
3. Login API 호출에서 발급된 Token값을 provider value에 set(저장)
본인 환경에서는 로그인 성공시 서버에서는 response header에 token을 적재하여 보내주고 있다.
로그인 하는 컴포넌트와 로그인 후 이동하는 컴포넌트가 react route의 navigate로 이동하고 있어 props로 데이터 전송이 불가했다.
서버에서 response를 받고 context provider value에 저장하자
import style from '../../style/./page/LoginPage.module.css' import React, {useContext, useEffect, useState} from "react"; import {useNavigate} from "react-router-dom"; import axios from "axios"; import Alert from "../component/Alert"; import { tkContext } from "../../tkContext"; // 1. 생성한 컨텍스트 import const ManagerLoginPage = () => { // ...코드생략 // Route navigate const navigate = useNavigate(); const toLoginPage = () => { navigate('/'); } const toManagementPage = () => { navigate('/management'); } const enterKeyEvent = (e) => { if(e.key === 'Enter') { managerLogin(); } } // ...코드생략 // 2. Token Context 사용 선언 const { setToken } = useContext(tkContext); const managerLogin = async () => { try { const response = await axios.post('http://localhost:8080/api/auth/managerSignIn', { email: email, password: password, }); if (response.status === 200) { if(response.data.result === true) { const authorizationHeader = response.headers['authorization']; if (authorizationHeader) { // 응답 헤더의 authorizationHeader에서 토큰 분리 후 provider의 setToken으로 전역으로 값을 저장 const newToken = authorizationHeader.split('Bearer ')[1]; setToken(newToken); // ...코드생략 } catch (error) { // request error addAlert('error', error, 3); } } return ( <div className={style.backgroundContainer}> {/* ...코드생략 */} </div> ); }; export default ManagerLoginPage;
4. Route navigate로 이동한 페이지에서 Token값 꺼내 쓰기
본인 환경에서는 로그인 성공한 후 토큰을 저장하고 다른 페이지로 이동한다.
또한 이동한 패이지 내부의 특정 컴포넌트에서 API를 요청할 때 전역 변수로 저장한 token값을 꺼내서 사용해야 했다.
사용은 다음과 같다.
import style from '../../style/component/CreateAccount.module.css'; import React, {useContext, useState} from "react"; import axios from "axios"; import { tkContext } from "../../tkContext"; // 1. Context 불러오기 const CreateAccount = ({addAlert}) => { //... 코드 생략 // 2. Token 사용을 위해 등록 const { token } = useContext(tkContext); // tkContext 구독 const singUp = async () => { try { const response = await axios.post( 'http://localhost:8080/api/auth/signUp', { name: name, email: email, password: password, confirmPassword: confirmPassword, phoneNumber: phoneNumber, userType: userType, }, { headers: { Authorization: `Bearer ${token}` // 3. 불러온 토큰 사용 } } ); // ...코드생략 } return ( <div className={style.formContainer}> {/* ...코드생략 */} </div> ) }; export default CreateAccount;
결과
'DEV > react' 카테고리의 다른 글
React Three Fiber (react-three) 메모장 1 (4) 2024.10.07 React Error : autoprefixer: start/end value has mixed support, consider using flex-start/end instead (0) 2024.04.18 React App build 명령어 (0) 2024.02.20 React Component 가변적으로 생성/추가하기, 제거하기 (Alert 가변 생성 예시 포함) (0) 2024.02.19 React Javascript 키 입력 이벤트 "onKeyPress is deprecated..." onKeyDown, onKeyUp을 쓰자. (0) 2024.02.16