React-5

mh·2022년 1월 7일
0

React

목록 보기
5/5
post-thumbnail

React context

React.createContext | React
useContext | React

React context를 사용하면 특정한 데이터를 authContext가 감싼 범위내의 컴포넌트에서도 업데이트 하고 사용 할 수 있다.

내가 이해한대로 그려봤다

본래 부모컴포넌트에서 하나씩 상속 받아야할 데이터를 contextProvider 내의 컴포넌트라면 context에서 받아쓸 수 있다.
여기서 isAuth라는 true일때 로그인상태고 false이면 로그아웃인 state가 있을때 ,
컴포넌트가 컨텍스트에서 isAuth값을 상속해서 어떤 컴포넌트를 가도 로그인 / 아웃 상태를 유지 할 수 있다.
또한 context에서 isAuth의 데이터를 업데이트하여 로그인/아웃 상태를 변경 할 수 있다.

Context 만들기

function App() {
  return (
    <Routes>
      <Route path="/" element={<LandingPage />}></Route>
      <Route path="/login" element={<LoginPage />}></Route>
      <Route path="/register" element={<RegisterPage />}></Route>
    </Routes>
  );
}

여기서 Routes안의 모든 컴포넌트안에서 Context를 사용하려한다면
react 내장함수인 createContext를 사용한다.
const AuthContext = createContext(); 선언해준다.
import React, { createContext } from 'react'; 자동으로 추가된다.

Context Provider 만들기


const yourContext = createContext();
const yourValue = "hello world";
const yourFunc = (x, y) => x + y;

<yourContext.Provider value = {yourValue,yourFunc}>
  <App/>
</yourContext.Provider>
  • context의 state값은 Provider로 감싸준 범위안에서 사용가능하다.

  • yourValue yourFunc
    value에 들어갈 값, App 컴포넌트에서 사용할 데이터, 데이터를 업데이트하는 함수

  • 여기서 <App/> 컴포넌트는 Provider의 범위내에 있기 때문에 Provider의 value값을 언제든지 사용할 수 있다.

function App() {

  const AuthContext = createContext();
  const yourValue = 'Hello World'
  
  return (
    <AuthContext.Provider value={yourValue}>
      <Routes>
        <Route path="/" element={<LandingPage />}></Route>
        <Route path="/login" element={<LoginPage />}></Route>
        <Route path="/register" element={<RegisterPage />}></Route>
      </Routes>
    </AuthContext.Provider>
  );
}


좀더 복잡한 로직을 구현하기 위해서 context도 컴포넌트처럼 폴더를 따로 만들어주고 context마다 파일을 생성한다.

// src/context/AuthContext.js

import { createContext } from "react";

export const AuthContext = createContext;

const AuthContextProvider = ({children}) => {
    return (
        <AuthContext.Provider value>
            {children}
        </AuthContext.Provider>
    )
}

export default AuthContextProvider;

이런식으로 파일 따로 빼서 프랍에 children을 넣어주고 children요소를 감싸주는 함수를 만든다.

이걸 export default로 빼와서 App.js 에 적용한다

// /src/App.js
import './App.css';
import React from 'react';
import { Route, Routes } from 'react-router-dom';
import LandingPage from './pages/LandingPage/LandingPage';
import LoginPage from './pages/LoginPage/LoginPage';
import RegisterPage from './pages/RegisterPage/RegisterPage';
import AuthContextProvider from './context/AuthContext';

function App() {
  return (
    <AuthContextProvider>
      <Routes>
        <Route path="/" element={<LandingPage />}></Route>
        <Route path="/login" element={<LoginPage />}></Route>
        <Route path="/register" element={<RegisterPage />}></Route>
      </Routes>
    </AuthContextProvider>
  );
}

export default App;

AuthContextProvider함수를 <>에 담아서 Routes부터 아래의 컴포넌트들을 감싸주고 import문을 작성해준다.

Provider에 함수 만들기

// src/context/AuthContext.js

import { createContext } from "react";

export const AuthContext = createContext();

const AuthContextProvider = ({children}) => {
    return (
        <AuthContext.Provider value>
            {children}
        </AuthContext.Provider>
    )
}

export default AuthContextProvider;

AuthContextProvider에서 필요한 value값을 선언하여 사용할 수 있고,
함수를 사용하여 값을 업데이트 할 수 도있다.

필요한 데이터를 보내주는 함수

초기 로그인 정보 -> 로그인 상태가 아님

import { createContext } from "react"

export const AuthContext = createContext();


function AuthContextProvider ({children}) => {
  const [isAuth,setIsAuth] = useState(false);
  const AuthContextData = {
    isAuth,
  }
  
  return (
    <AuthContext.Provider value={AuthContextData}>
      {children}
    </AuthContext.Provider>
  )
  
export default AuthContextProvider; 

로그인 유무정보가 담긴 값을 isAuth라 선언하고
초기사용자는 로그인정보가 없으니 state 값을 false로 한다.
isAuth값을 AuthContextData로 객체로 선언하고
Provider 나눠줄 valueisAuth값을 받기위해 AuthContextData의 값을 받는다.
이제 children에 들어있는 모든 컴포넌트안에서 isAuth값을 받을 수 있다.

데이터(isAuth)를 업데이트해주는 함수

서버에서 받은 토큰을 다시 서버에 전달해주기

Customer.isAuthenticated | JavaScript API 레퍼런스 | 클레이풀
설치 및 코드 연동하기 | 클레이풀 ( options 값 안내 )

//클레이풀 고객로그인여부 확인 API
var Customer = Clayful.Customer;

var options = {
	...
};

Customer.isAuthenticated(options, function(err, result) {

	if (err) {
		// Error case
		console.log(err.code);
	}

	var headers = result.headers;
	var data = result.data;

	console.log(data);

});
Customer.isAuthenticated 란 함수가 options값을 받고 고객의 로그인여부를 판단한다.
AuthContext.js 파일에 이 코드를 추가한다.
import { useState , createContext } from 'react';
import Clayful from 'clayful/client-js';

export const AuthContext = createContext();

function AuthContextProvider ({children}) {
const [isAuth,setIsAuth] = useState(false);

  //클레이풀 고객로그인여부 확인 API
const isAuthenticated = () => {
  var Customer = Clayful.Customer;

  var options = {
      customer:localStorage.getItem("accessToken")
  };

  Customer.isAuthenticated(options, function(err, result) {

      if (err) {
          // Error case
          console.log(err.code);
        setIsAuth(flase);
      }

      var headers = result.headers;
      var data = result.data;
      
      if (isAuthenticated) {
        setIsAuth(true)
      } else {
        setIsAuth(false)
      }
    
      console.log(data);
      

  });
}

  const AuthContextData = {
    isAuth,
    isAuthenticated
  }
  
  return(
    <AuthContext.Provider vlaue={AuthContextdata}>
      {children}
    </AuthContext.Provider>
  )
}
  1. const isAuthenticated = ()=>{} 클레이풀 코드를 함수로 선언해준다.

  2. import Clayful from 'clayful/client-js'; 클레이풀 서비스를 이용하기 위해 Clayfulimport한다.

  3. options 에는 고객이 브라우저(로컬스토리지)에 가지고 있는 토큰을 넣는다.
    customer:localStorage.getItem("accessToken")
    집어넣을때setItem와 반대로 getItem을 써서 토큰값을 localStorage로 부터 꺼낸다.

var options = {
      customer : localStorage.getItem("accessToken")
  };
  1. if (err) 서버에서 에러를 응답했을때 setIsAuthstatefalse로 설정한하고 return으로 반환 후 종료한다.
if (err) {
        // Error case
        console.log(err.code);
        setIsAuth(flase);
        return;
      }
  1. if (isAuthenticated) 서버에서 사용자 토큰값이 맞다고 판단하면 setIsAuth(true)statetrue로 설정한다. 아니라면 false로 설정한다.
      var headers = result.headers;
      var data = result.data;
      
      if (isAuthenticated) {
        setIsAuth(true)
      } else {
        setIsAuth(false)
      }
  1. AuthContextData에 state를 업데이트 시켜주는 함수인isAuthenticated을 넣어준다.
  const AuthContextData = {
	isAuth,
    isAuthenticated
  }

이로서 Provider 내의 모든 컴포넌트에서 isAuth의 정보를 받아볼수있고 업데이트도 할수 있게 되었다.

로그아웃 기능 추가

import {useNavigate} from 'react-router-dom';
const navigate = useNavigate();

...

const signOut = () => {
  setIsAuth(false);
  customer : localStorage.removeItem("accessToken");
  navigate("/login");

...

const AuthContextData = {
  isAuth,
  isAuthenticated,
  signOut,
}
  1. signOut 함수 생성

  2. 실행시 setIsAuth 값을 false로 ->로그아웃

  3. customer.localStorage.removeItem("accessToken") -> 로컬 토큰 삭제

  4. navigate("/login") -> 로그아웃 시 로그인 페이지로 이동시킴

  5. AuthContextData 에 signOut 함수 추가

로그인 유지 전체 코드

import React, { createContext, useState } from "react";
import { useNavigate } from "react-router-dom";
import Clayful from "clayful/client-js";

export const AuthContext = createContext();

const AuthContextProvider = ({children}) => {
    const navigate = useNavigate();
    const [isAuth,setIsAuth] = useState(false);
    
        //클레이풀 고객로그인여부 확인 API
    const isAuthenticated = () => {    
        var Customer = Clayful.Customer;

        var options = {
            customer : localStorage.removeItem("accessToken")
        };

        Customer.isAuthenticated(options, function(err, result) {

            if (err) {
                // Error case
                console.log(err.code);
                setIsAuth(false);
                return;
            }

            var headers = result.headers;
            var data = result.data;

            if (isAuthenticated) {
                setIsAuth(true);
            } else {
                setIsAuth(false);
            }

            console.log(data);

        });

    }

    const signOut = () => {
        setIsAuth(false);
        customer : localStorage.removeItem("accessToken");
        navigate("/login");
    }

    const AuthContextData = {
        isAuth,
        isAuthenticated,
        signOut,
    }

    return (
        <AuthContext.Provider value={AuthContextData}>
            {children}
        </AuthContext.Provider>
    )
}

export default AuthContextProvider;

다른 컴포넌트에서 Context 가져다 쓰기

AuthContext.js 파일의 로그인유지,아웃 context를 login.js 컴포넌트에서 사용해보자.

//App.js
import './App.css';
import React from 'react';
import { Route, Routes } from 'react-router-dom';
import LandingPage from './pages/LandingPage/LandingPage';
import LoginPage from './pages/LoginPage/LoginPage';
import RegisterPage from './pages/RegisterPage/RegisterPage';
import AuthContextProvider from './context/AuthContext';

function App() {
  return (
    <AuthContextProvider>
      <Routes>
        <Route path="/" element={<LandingPage />}></Route>
        <Route path="/login" element={<LoginPage />}></Route>
        <Route path="/register" element={<RegisterPage />}></Route>
      </Routes>
    </AuthContextProvider>
  );
}

export default App;

App.js에서 AuthContextProvider<Route path="/login" element={<LoginPage />}></Route> 를 감싸고 있기 때문에 loginPage컴포넌트에서도 AuthContext.jsContext를 사용할 수 있다.

// /src/components/login.js
import React, { useContext, useState } from 'react'
import { Link , useNavigate } from 'react-router-dom'
import Clayful from 'clayful/client-js'
import { AuthContext } from '../../context/AuthContext';

function LoginPage() {
    const navigate = useNavigate();
    const [email, setEmail] = useState("")
    const [password, setPassword] = useState("")

    //컨텍스트 불러오기
    const {isAuthenticated} = useContext(AuthContext);
    
    const handleEmailChange = (e) => {
        setEmail(e.target.value);
    }

    const handlePasswordChange = (e) => {
        setPassword(e.target.value);
    }
    
    const handleSubmit = (e) => {
        e.preventDefault()

        var Customer = Clayful.Customer;

        var payload = {
            // userId:   'user_id',
            email,
            password,
        };

        Customer.authenticate(payload, function(err, result) {

            if (err) {
                // Error case
                console.log(err.code);
            }

            var data = result.data;
            
            console.log(data);

            localStorage.setItem('cutomerUid',data.customer)
            localStorage.setItem('accessToken',data.token)

            

            navigate("/")
            isAuthenticated();
        });

    }

    return (
        <div className="auth-wrapper">
            <section>
                <h1 className="sr-only">로그인 페이지</h1>
                <h2><span className="green">로그인</span> 하고 특별한 혜택누리기</h2>
                <p className='gray'>계정을 잊어버리셨나요? <Link to="javascript:void(0)" className="green">같이 찾으러 가요!</Link></p>
                <form onSubmit={handleSubmit}>
                    
                    <label className="gray" for="email">
                        <input 
                        onChange={handleEmailChange} name="email" placeholder="ID를 입력해주세요" type="email" value={email} />
                        
                    </label>
                    
                    <label className="gray" for="email">
                        <input 
                        onChange={handlePasswordChange} placeholder="비밀번호를 입력해주세요" type="password" value={password} />
                        아기사자 ID는 심바, 사바나, 치타는웃고있다 서비스에 로그인할때 사용되는 Email 주소에요.
                    </label>
                    <p className='gray'>아기사자 서비스가 처음이신가요?<Link to="register" className="green"> 계정 만들러가기!</Link></p>
                    <button type="submit">VVIP 나가신다!</button>
                </form>
            </section>
        </div>
    )
}

export default LoginPage
  1. useContext로 컨텍스트를 불러온다. const context = useContext(contextValue)

useContext | React

loginPage 함수 컴포넌트 안에서
const {isAuthenticated} = useContext(AuthContext); 로 사용할 컨텍스트를 불러온다.

  1. import AuthContextProvider from './context/AuthContext';로 컨텍스트를 import한다.

  2. navigate('/')로 루트페이지로 날리는 다음 코드에 isAuthenticated() 함수를 추가한다.

  • 오늘의 에러
    authContext.js의
    export const AuthContext = createContext; 에서 ()를 빼먹었다.
    -> export const AuthContext = createContext();
profile
🤪🤪🤪🤪🤪

0개의 댓글