9. 리액트 소셜 로그인

minii_
|2024. 10. 31. 20:36
반응형

1. 카카오 애플리케이션 설정

  • 카카오에 접근하기 위한 인가 코드
  • access 토큰
  • 사용자 정보를 얻어 옴

구현 방식

→ 카카오나 네이버 서비스는 ‘권한부여 승인 코드 방식

 

 

https://developers.kakao.com/

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

해당 사이트에서 로그인 후 진행

 

애플리케이션 추가하기

생성 후 '앱 키'에서 REST API 키 복사해 두기

 

Web 플랫폼 등록

 

'등록하러 가기' 선택

 

Redirect URI 설정

 

카카오 로그인에서 활성화 설정 ON

카카오 로그인 > 동의항목

닉네임 필수로 받도록 설정

 

 

2. 인가코드 받기

코드 생성 후 복사해서 기억

 

const rest_api_key = '2d1ed6e23cf3321aa56ae284e2c76e38'
const redirect_uri = 'http://localhost:3000/member/kakao'

const auth_code_path = `https://kauth.kakao.com/oauth/authorize`

export const getKakaoLoginLink = () => {

    const kakaoURL = `${auth_code_path}?client_id=${rest_api_key}&redirect_uri=${redirect_uri}&response_type=code`

    return kakaoURL
}

src\api\kakaoApi.js

 

import React from 'react'
import { getKakaoLoginLink } from '../../api/kakaoApi'
import { Link } from 'react-router-dom'

const link = getKakaoLoginLink()

function KakaoLoginComponent(props) {
  return (
    <div className="flex flex-col">
        <div className="text-center text-blue-500">로그인시에 자동 가입처리 됩니다</div>
            <div className="flex justify-center w-full">
            <div
            className="text-3xl text-center m-6 text-white font-extrabold w-3/4 bg-yellow-500 shadow-smrounded p-2">
            <Link to={link}>KAKAO LOGIN</Link>
            </div>
        </div>
    </div>
  )
}

export default KakaoLoginComponent

src\components\member\KakaoLoginComponent.js

 

src\components\member\LoginComponent.js에 작성한 KakaoLoginComponent가 보이도록 추가

 

카카오로 로그인이 가능하면 닉네임을 필수로 설정해 둔 것까지 확인

 

import { useSearchParams } from"react-router-dom";

const KakaoRedirectPage = () =>{

  const [searchParams] = useSearchParams()

  const authCode = searchParams.get("code")

    return(

    <div>
      <div>Kakao Login Redirect</div>
      <div>{authCode}</div>
    </div>

    )
  }
export default KakaoRedirectPage;

src\pages\member\KakaoRedirectPage.js

 

import { Suspense, lazy } from "react";

const Loading = <div>Loading....</div>
const Login =  lazy(() => import("../pages/member/LoginPage"))
const Logout =  lazy(() => import("../pages/member/LogoutPage"))
const KakaoRedirect = lazy(() => import("../pages/member/KakaoRedirectPage"))

const memberRouter = () => {

  return [
    {
      path:"login",
      element: <Suspense fallback={Loading}><Login/></Suspense>
    },
    {
      path:"logout",
      element: <Suspense fallback={Loading}><Logout/></Suspense>
    },
    {
      path:"kakao",
      element: <Suspense fallback={Loading}><KakaoRedirect/></Suspense>
    }

  ]

}

export default memberRouter

src\router\memberRouter.js

 

여러 번 테스트해야 하기 때문에 시크릿 모드로 하는 걸 추천

 

인가코드를 받을 수 있음

 

 

3. 카카오 Access 토큰 받기

https://developers.kakao.com/docs/latest/ko/rest-api/reference

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

참고자료

 

import axios from "axios";

const rest_api_key = '2d1ed6e23cf3321aa56ae284e2c76e38';
const redirect_uri = 'http://localhost:3000/member/kakao';

const auth_code_path = `https://kauth.kakao.com/oauth/authorize`;
const access_token_url = 'https://kauth.kakao.com/oauth/token';

export const getKakaoLoginLink = () => {
    const kakaoURL = `${auth_code_path}?client_id=${rest_api_key}&redirect_uri=${redirect_uri}&response_type=code`;
    return kakaoURL;
}

export const getAccessToken =async(authCode) =>{
    const header= {
        headers:{"Content-Type": "application/x-www-form-urlencoded;charset=utf-8"}
    }
    const params= {
        grant_type:"authorization_code",
        client_id:rest_api_key,
        redirect_uri:redirect_uri,
        code:authCode
    }
    const res= await axios.post(access_token_url, params , header)
    const accessToken=res.data.access_token
    return accessToken
}

src\api\kakaoApi.js

 

import { useEffect } from "react";
import { useSearchParams } from"react-router-dom";
import { getAccessToken } from "../../api/kakaoApi";

const KakaoRedirectPage = () =>{

  const [searchParams] = useSearchParams()

  const authCode = searchParams.get("code")

  useEffect(() =>{
    getAccessToken(authCode).then(data=>{
    console.log(data)
    })
    }, [authCode])

    return(

    <div>
      <div>Kakao Login Redirect</div>
      <div>{authCode}</div>
    </div>

    )
  }
export default KakaoRedirectPage;

src\pages\member\KakaoRedirectPage.js

useEffect 훅을 사용하여 authCode 값이 변경될 때마다 getAccessToken 함수를 호출하고 accessToken을 콘솔에 출력한다.

 

해당 설정까지 완료되면 액세스 토큰을 받아올 수 있다.

 

4. API 서버에서 사용자 정보 추출하기 1

package org.zerock.apiserver.service;

import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
import org.zerock.apiserver.dto.MemberDTO;
import org.zerock.apiserver.repository.MemberRepository;

import java.util.LinkedHashMap;

@Service
@RequiredArgsConstructor
@Log4j2
public class MemberServiceImpl implements MemberService{

    private final MemberRepository memberRepository;

    @Override
    public MemberDTO getKakaoMember(String accessToken) {

        //accessToken을 이용해서 사용자 정보 가져오기
        getEmailFromKakaoAccessToken(accessToken);

        //기존 DB에 회원 정보가 있는 경우 / 없는 경우

        return null;
    }

    private void getEmailFromKakaoAccessToken(String accessToken) {

        String kakaoGetUserURL = "https://kapi.kakao.com/v2/user/me";

        RestTemplate restTemplate = new RestTemplate();

        HttpHeaders headers = new HttpHeaders();
        headers.add("Authorization", "Bearer " + accessToken);
        headers.add("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");

        HttpEntity<String> entity = new HttpEntity<>(headers);

        UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(kakaoGetUserURL).build();

        ResponseEntity<LinkedHashMap> response =
                restTemplate.exchange(uriComponents.toString(), HttpMethod.GET, entity, LinkedHashMap.class);

        log.info("response----------------");
        log.info(response);
    }
}

org/zerock/apiserver/service/MemberServiceImpl.java

카카오 OAuth 액세스 토큰을 사용해 사용자 정보를 요청하고 응답을 로깅하는 기능

Bearer 뒤에 꼭 공백이 하나 있어야 한다... 주의하기

 

5. API 서버에서 사용자 정보 추출하기 2

import axios from "axios";
import { API_SERVER_HOST } from "./todoApi";

const rest_api_key = '2d1ed6e23cf3321aa56ae284e2c76e38';
const redirect_uri = 'http://localhost:3000/member/kakao';

const auth_code_path = `https://kauth.kakao.com/oauth/authorize`;
const access_token_url = 'https://kauth.kakao.com/oauth/token';

export const getKakaoLoginLink = () => {
    const kakaoURL = `${auth_code_path}?client_id=${rest_api_key}&redirect_uri=${redirect_uri}&response_type=code`;
    return kakaoURL;
}

export const getAccessToken =async(authCode) =>{
    const header= {
        headers:{"Content-Type": "application/x-www-form-urlencoded;charset=utf-8"}
    }
    const params= {
        grant_type:"authorization_code",
        client_id:rest_api_key,
        redirect_uri:redirect_uri,
        code:authCode
    }
    const res= await axios.post(access_token_url, params , header)
    const accessToken=res.data.access_token
    return accessToken
}   

export const getMemberWithAccessToken = async (accessToken) => {

    const res = await axios.get(`${API_SERVER_HOST}/api/member/kakao?accessToken=${accessToken}`)

    return res.data
}

src\api\kakaoApi.js

 

import { useEffect } from "react";
import { useSearchParams } from"react-router-dom";
import { getAccessToken, getMemberWithAccessToken } from "../../api/kakaoApi";

const KakaoRedirectPage = () =>{

  const [searchParams] = useSearchParams()

  const authCode = searchParams.get("code")

  useEffect(() =>{
    getAccessToken(authCode).then(accessToken=>{

        getMemberWithAccessToken(accessToken).then(result => {
          console.log("----------------")
          console.log(result) 
        })
      })
    }, [authCode])

    return(

    <div>
      <div>Kakao Login Redirect</div>
      <div>{authCode}</div>
    </div>

    )
  }
export default KakaoRedirectPage;

src\pages\member\KakaoRedirectPage.js

 

package org.zerock.apiserver.controller;

import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.zerock.apiserver.service.MemberService;

@RestController
@Log4j2
@RequiredArgsConstructor
public class SocialController {

    private final MemberService memberService;

    @GetMapping("/api/member/kakao")
    public String[] getMemberFromKakao(String accessToken) {

        log.info("accessToken: " + accessToken);

        memberService.getKakaoMember(accessToken);


        return new String[]{"AAA", "BBB", "CCC"};

    }
}

org/zerock/apiserver/controller/SocialController.java

 

로그인을 하면 백엔드에 response 로그와 사용자 정보가 출력이 된다.

-> 사용자 정보 추출

이메일 주소를 사용할 수 없기 때문에 닉네임을 사용해서 이메일을 만드는 방법을 사용한다.

 

6. API 서버에서 소셜 회원 처리

기존의 회원과 새로운 회원 관리 

  • DB에 없을 경우 사용자 추가
  • DB에 이미 존재할 경우 이메일(닉네임)로 조회하여 전달

 

org/zerock/apiserver/service/MemberServiceImpl.java

카카오 API를 통해 사용자 정보(nickname)를 가져오는 코드 추가

accessToken을 사용하여 사용자 정보를 JSON 형식으로 반환하며, 이 정보를 LinkedHashMap으로 처리

*LinkedHashMap: 자바에서 제공하는 Map 인터페이스의 구현체 중 하나로, 키-값 쌍을 저장하는 자료구조

 

 

package org.zerock.apiserver.service;

import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
import org.zerock.apiserver.domain.Member;
import org.zerock.apiserver.domain.MemberRole;
import org.zerock.apiserver.dto.MemberDTO;
import org.zerock.apiserver.repository.MemberRepository;

import java.util.LinkedHashMap;
import java.util.Optional;

@Service
@RequiredArgsConstructor
@Log4j2
public class MemberServiceImpl implements MemberService{

    private final MemberRepository memberRepository;

    private final PasswordEncoder passwordEncoder;

    @Override
    public MemberDTO getKakaoMember(String accessToken) {

        //accessToken을 이용해서 사용자 정보 가져오기
        //카카오 연동 닉네임 -- 이메일 주소에 해당
        String nickname = getEmailFromKakaoAccessToken(accessToken);

        //기존 DB에 회원 정보가 있는 경우 / 없는 경우
        Optional<Member> result = memberRepository.findById(nickname);

        if(result.isPresent()) {

            //return
        }

        Member socialMember = makeSocialMember(nickname);

        memberRepository.save(socialMember);

        MemberDTO memberDTO = entityToDTO(socialMember);

        return  memberDTO;
    }

    private Member makeSocialMember(String email){

        String tempPassword = makeTempPassword();

        log.info("tempPassword: " + tempPassword);

        Member member = Member.builder()
                .email(email)
                .pw(passwordEncoder.encode(tempPassword))
                .nickname("Social Member")
                .social(true)
                .build();

        member.addRole(MemberRole.USER);

        return member;
    }

    private String getEmailFromKakaoAccessToken(String accessToken) {

        String kakaoGetUserURL = "https://kapi.kakao.com/v2/user/me";

        RestTemplate restTemplate = new RestTemplate();

        HttpHeaders headers = new HttpHeaders();
        headers.add("Authorization", "Bearer " + accessToken);
        headers.add("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");

        HttpEntity<String> entity = new HttpEntity<>(headers);

        UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(kakaoGetUserURL).build();

        ResponseEntity<LinkedHashMap> response =
                restTemplate.exchange(uriComponents.toString(), HttpMethod.GET, entity, LinkedHashMap.class);

        log.info("response----------------");
        log.info(response);

        LinkedHashMap<String, LinkedHashMap> bodyMap = response.getBody();

        LinkedHashMap<String, String> kakaoAccount = bodyMap.get("properties");

        log.info("kakaoAccount: " + kakaoAccount);

        String nickname = kakaoAccount.get("nickname");

        log.info("nickname: " + nickname);

        return  nickname;
    }

    //10자리의 패스워드를 만듦
    private String makeTempPassword() {

        StringBuffer buffer = new StringBuffer();

        for (int i = 0; i < 10; i++) {
            buffer.append((char) ((int)(Math.random() * 55) + 65));
        }
        return buffer.toString();
    }
}

org/zerock/apiserver/service/MemberServiceImpl.java 전체 코드

 

package org.zerock.apiserver.service;

import org.springframework.transaction.annotation.Transactional;
import org.zerock.apiserver.domain.Member;
import org.zerock.apiserver.dto.MemberDTO;

import java.util.stream.Collectors;

@Transactional
public interface MemberService {

    MemberDTO getKakaoMember(String accessToken);

    default MemberDTO entityToDTO(Member member) {

        MemberDTO dto = new MemberDTO(
                member.getEmail(),
                member.getPw(),
                member.getNickname(),
                member.isSocial(),
                member.getMemberRoleList().stream().map(memberRole -> memberRole.name()).collect(Collectors.toList()));

        return dto;
    }

}

org/zerock/apiserver/service/MemberService.java 전체 코드

 

select * from member;

현재는 내 닉네임에 맞는 사용자가 없음

 

다시 로그인을 진행하면 닉네임으로 사용자가 추가되는 것을 확인할 수 있음

 

이미 access Token을 가지고 왔기 때문에 인증이 끝난 사용자의 닉네임과 이메일은 확실한 것임

따라서 이메일로 조회만 하면 됨

 

accessToken을 발행받았다는 것은 이미 사용자에 대한 인증이 끝났기 때문에 사용자가 DB에 있는지만 확인하면 된다.

다시 로그인하고 로그를 확인하면 이미 DB에 존재하는 회원이기 때문에 existed 로그를 확인할 수 있다.

 

7. API 서버와 리액트 연동 확인

package org.zerock.apiserver.controller;

import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.zerock.apiserver.dto.MemberDTO;
import org.zerock.apiserver.service.MemberService;
import org.zerock.apiserver.util.JWTUtil;

import java.util.Map;

@RestController
@Log4j2
@RequiredArgsConstructor
public class SocialController {

    private final MemberService memberService;

    @GetMapping("/api/member/kakao")
    public Map<String, Object> getMemberFromKakao(String accessToken) {

        log.info("accessToken: " + accessToken);

        MemberDTO memberDTO = memberService.getKakaoMember(accessToken);

        Map<String, Object> claims = memberDTO.getClaims();

        String jwtAccessToken = JWTUtil.generateToken(claims, 10);
        String jwtRefreshToken = JWTUtil.generateToken(claims, 60*24);

        claims.put("accessToken", jwtAccessToken);
        claims.put("refreshToken", jwtRefreshToken);

        return claims;

    }
}

org/zerock/apiserver/controller/SocialController.java

클레임 정보와 만료 시간을 바탕으로 JWT 토큰을 생성하여 반환(10분, 24시간)

콘솔창에서 정보 확인이 가능해짐

이제 해당 정보들로 로그인을 시도

 

src\slices\loginSlice.js

기존에 사용하던 코드에서 setCookie 함수를 추가하여 login 함수가 호출될 때 사용자의 정보를 쿠키에 저장하도록 한다.

 

import { useEffect } from "react";
import { useSearchParams } from"react-router-dom";
import { getAccessToken, getMemberWithAccessToken } from "../../api/kakaoApi";
import { login } from "../../slices/loginSlice";
import { useDispatch } from "react-redux";

const KakaoRedirectPage = () =>{

  const [searchParams] = useSearchParams()

  const authCode = searchParams.get("code")

  const dispatch = useDispatch(); 

  useEffect(() =>{
    getAccessToken(authCode).then(accessToken=>{

        getMemberWithAccessToken(accessToken).then(result => {
          console.log("----------------")
          console.log(result) 
          dispatch(login(result))
        })
      })
    }, [authCode])

    return(

    <div>
      <div>Kakao Login Redirect</div>
      <div>{authCode}</div>
    </div>

    )
  }
export default KakaoRedirectPage;

src\pages\member\KakaoRedirectPage.js

로그인한 사용자 정보를 업데이트하도록 dispatch 추가

다시 로그인 후 쿠키를 확인하면 member가 만들어져 있음

이 상태에서 쿠키를 우클릭으로 삭제하고 about 페이지에 들어간다.

 

그리고 다시 로그인을 하면 member가 다시 만들어진다.

-> 여기까지 하면 Todo까지 구현 완료

 

src\pages\member\KakaoRedirectPage.js

작성해 둔 useCustomLogin을 사용해서 페이지 이동 처리를 한다.

로그아웃 후 다시 로그인하면 modify 페이지로 이동한다.

 

social 사용자의 ture 값을 flase로 바꿔준다.

update member set social = false where email = '이성민'

 

member 쿠키를 삭제하고

소셜 로그인을 하면 위와 같이 메인 페이지도 이동하게 된다.

 

 

8. 리액트 사용자 정보 수정

delete from member_member_role_list where member_email = '이성민';

delete from member where email = '이성민';

소셜 사용자 지우기

 

import React, { useEffect, useState } from 'react'
import { useSelector } from 'react-redux'

const initState = {
    email:'',
    pw:'',
    nickname:''
}

function ModifyComponent() {

    const [member, setMember] = useState(initState)

    const loginInfo = useSelector(state => state.loginSlice)

    useEffect(() => {

        setMember({...loginInfo, pw:'ABCD'})
    }, [loginInfo])

    const handleChange = (e) => {

        member[e.target.name] = e.target.value

        setMember({...member})
    }

  return (
    <div className='mt-6'>
        <div className='flex justify-center'>
            <div className='relative mb-4 flex w-full flex-wrap items-stretch'>
                <div className='w-1/5 p-6 text-right font-bold'>Email</div>
                <input className='w-4/5 p-6 rounded-r border border-solid border-neutral-300 shadow-md'
                    name="email"
                    type={'text'}
                    value={member.email}
                    readOnly
                >    
                </input>
            </div>
        </div>
        <div className="flex justify-center">
            <div className="relative mb-4 flex w-full flex-wrap items-stretch">
                <div className="w-1/5 p-6 text-right font-bold">Password</div>
                    <input className="w-4/5 p-6 rounded-r border border-solid border-neutral-300 shadow-md"
                        name="pw" 
                        type={'password'}
                        value={member.pw} 
                        onChange={handleChange} 
                    >
                    </input>
                </div>
        </div>
        <div className="flex justify-center">
            <div className="relative mb-4 flex w-full flex-wrap items-stretch">
                <div className="w-1/5 p-6 text-right font-bold">Nickname</div>
                    <input className="w-4/5 p-6 rounded-r border border-solid border-neutral-300 shadow-md"
                        name="nickname" 
                        type={'text'} 
                        value={member.nickname} 
                        onChange={handleChange} 
                    >
                </input>
            </div>
        </div>
            <div className="flex justify-center">
                <div className="relative mb-4 flex w-full flex-wrap justify-end">
                <button type="button"
                    className="rounded p-4 m-2 text-xl w-32 text-white bg-blue-500" 
                    > 
                    Modify 
                </button>
            </div>
        </div>
    </div>
 );
 }
 export default ModifyComponent;

src\components\member\ModifyComponent.js

 

import React from 'react'
import BasicLayout from "../../layouts/BasicLayout"
import ModifyComponent from '../../components/member/ModifyComponent'

function ModifyPage() {
  return (
    
    <BasicLayout>
        <div className='text-3xl'>Member Modify Page</div>

        <div className='bg-white w-full mt-4 p-2'>
            <ModifyComponent></ModifyComponent>
        </div>
    </BasicLayout>
  )
}

export default ModifyPage

src\pages\member\ModifyPage.js

사용자가 회원 정보를 수정할 수 있는 페이지 작성

 

import { Suspense, lazy } from "react";

const Loading = <div>Loading....</div>
const Login =  lazy(() => import("../pages/member/LoginPage"))
const Logout =  lazy(() => import("../pages/member/LogoutPage"))
const KakaoRedirect = lazy(() => import("../pages/member/KakaoRedirectPage"))
const MemberModify = lazy(() => import("../pages/member/ModifyPage"))

const memberRouter = () => {

  return [
    {
      path:"login",
      element: <Suspense fallback={Loading}><Login/></Suspense>
    },
    {
      path:"logout",
      element: <Suspense fallback={Loading}><Logout/></Suspense>
    },
    {
      path:"kakao",
      element: <Suspense fallback={Loading}><KakaoRedirect/></Suspense>
    },
    {
      path:"modify",
      element: <Suspense fallback={Loading}><MemberModify/></Suspense>
    }

  ]

}

export default memberRouter

src\router\memberRouter.js 전체 코드(modify 라우터 부분만 추가)

 

 

이 쿼리들을 실행해서 사용자 정보를 지우고 다시 로그인을 한다.

 

처음 로그인을 하면 위와 같이 modify 페이지가 바로 보이게 된다.

Email은 ReadOnly로 설정하여 수정할 수 없음

 

9. 리액트 사용자 정보 수정 완료

package org.zerock.apiserver.dto;

import lombok.Data;

@Data
public class MemberModifyDTO {

    private String email;

    private String pw;

    private String nickname;

}

org/zerock/apiserver/dto/MemberModifyDTO.java

회원 정보를 수정할 때 필요한 데이터 전송 객체(DTO)

 

void modifyMember(MemberModifyDTO memberModifyDTO);

org/zerock/apiserver/service/MemberService.java 추가

 

org/zerock/apiserver/service/MemberServiceImpl.java

데이터베이스에 저장된 Member 엔티티의 정보를 수정

 

  • member.changeNickname(memberModifyDTO.getNickname());로 닉네임을 수정
  • member.changeSocial(false);로 소셜 회원 여부를 false로 변경
  • member.changePw(passwordEncoder.encode(memberModifyDTO.getPw()));로 비밀번호를 인코딩하여 저장
  • 수정된 member 객체를 memberRepository.save(member);를 통해 데이터베이스에 저장

 

 

src\api\memberApi.js

axios를 사용하여 회원 정보를 수정하기 위해 서버에 PUT 요청을 보내는 비동기 함수

 

src\components\member\ModifyComponent.js

버튼 클릭 시 modifyMember 함수를 호출하여 회원 정보를 수정

 

변경한 닉네임과 처음에 true였던 social값이 false로 변경됨

 

src\components\member\ModifyComponent.js

 

회원 정보를 수정하면 위와 같은 모달창이 뜬다.

 

close Modal 버튼을 누르면 다시 로그인 페이지가 뜨고

이름과 1111 패스워드로 로그인되는 것까지 확인했다.

반응형

'Web' 카테고리의 다른 글

11. 리액트 장바구니 구성  (0) 2024.11.07
10. 장바구니 API 만들기  (0) 2024.11.05
8. 리덕스 툴킷  (0) 2024.10.30
7. 시큐리티와 API 서버  (0) 2024.10.27
6. 리액트와 상품 API 서버 연동  (0) 2024.10.15