2024.02.16 TIL - 리액트 심화(redux toolkit, slice, json server, axios, interceptor, thunk, 리액트쿼리, throttling, debouncing, 인증/인가, JWT토큰)

Innes·2024년 2월 16일
0

TIL(Today I Learned)

목록 보기
67/147
post-thumbnail

📝 오늘의 공부

  • 리액트 심화 1회독 : 강의 내용 간략 정리
    • redux toolkit, slice, json server, axios, interceptor, thunk, 리액트쿼리, throttling, debouncing, 인증/인가, JWT토큰

Redux Toolkit

< 1강 >

  • toolkit : tool(편하게 쓰기 위한 도구), kit(도구를 간편하게 쓰기위한것)
    = 도구모음 패키지
yarn add @reduxjs/toolkit
npm install @reduxjs/toolkit
  • store 구성, action creator 간단하게 바꾸기 가능함!

  • creatstore 대신 : configureStore로 store 만들기

    • 인자는 객체(리듀서들)
  • 리듀서 파일에서 쓰는 API
    createSlice() : action creator, reducer 한번에 생성할 수 있음
    (createSlice 안에는 action creator, reducer 두개가 들어있는 것!)

따라서,
export 하려면 :

const counterSlice = createSlice({
// reducer의 이름, 초기 상태값
name: 'counter',
initialState: 'initialState',

// reducer들
reducers: {
	addNumber: (state, action) => {
    // state 변경하는 로직
      state.number = state.number + action.payload;
    },
    minusNumber: (state, action) => {
    // state 변경하는 로직
    },
  },
});

export default counterSlice.reducer;
export const { addNumber, minusNumber } = counterSlice.actions;

slice

< 2강 >

reducer대신 slice로 통합!~!~!
(action creator, reducer, action value까지 slice에 한번에 쓰는것!)

export로 action creator, reducer 두가지를 내보낼 수 있음!

// action creator 내보내기
export const { addTodo, removeTodo, switchTodo } = todoSice.actions;

// reducer 내보내기
export default todoSlice.reducer;

⭐️ npm i 에러 왜?
node_modules git ignore 안되는것도 이거때문인가?
강의에서도 yarn add 리덕스툴킷 해줬는데 그 다음에 npm i 하던데 왜 난 에러뜨지?
⭐️

  • redux toolkit 은 자동으로 불변성 유지해줌!!(immer라는 내장된 기능 덕분)

    • 기존 : [...state, action.payload];
    • redux toolkit : state.push(action.payload);
      이렇게 써줘도 불변성 자동으로 유지해줌~!~!
  • Redux Devtools : redux toolkit에 내장되어있음

    • action이 어떻게 흘러가는지를 보여주는 플러그인!
    • 크롬 브라우저 -> 확장프로그램으로 설치하면 끝

      ⭐️ 근데 자동으로 실행 안되는데? ㅠ ⭐️

  • Flux 패턴

    ⭐️ 첨부된 강의자료 필독 ⭐️


json-server

< 3강 >

  • json-server
    간단한 DB, API서버 생성해주는 패키지

  • 설치하기

npm install json-server
yarn add json-server
  • root 경로에 db.json file 만들기
    (키가 "" 로 되어있으면 json 파일임. 객체형식 아님 json형식임)

  • json server 시작하기
    가짜 서버가 리액트 local host 3001와 겹치지 않도록 '특정 포트'를 지정해주는게 좋음(--port 4000 이부분)
    json-server --watch db.json --port 4000

  • 브라우저에서 열기 : 이런식으로 접근하면 됨 (commetns의 1은 id)

local/host:4000/posts
local/host:4000/comments/1
  • 데이터를 실제 서버처럼 테스트할 수 있게 도와주는 가짜 서버만들기 가 바로 json-server

< 4강 >

  • '통신' 이란 ? communication
    웹 프로그래밍 세계에서의 대화! - 데이터로 이루어지는 대화
    서버(웹 서버) <-> 클라이언트(웹 브라우저)

  • 웹 통신은 약속이다! ( = 프로토콜)
    대화를 위해 미리 정해놓은 약속!
    약속한대로 대화해야됨(정해진 방식대로 데이터 주고받기)

  • 웹에서 서버 <-> 클라이언트 간에 대화할 땐 약속한대로 대화하자!
    (정해진 방식대로 데이터를 주고받자)
    => http 프로토콜

  • 요청(Request)과 응답(Reponse)
    서버에게 데이터 요청
    서버는 응답을 줌(데이터를 줌)

  • http 프로토콜의 메서드 - http 요청의 종류 (약속한걸 어떻게 쓸 것인가?)
    GET 조회
    POST 생성
    PUT, PATCH 수정(변경)
    DELETE 삭제
    ...등등

  • 상태코드 - 오류상태 보여주는 코드 ex) 404
    (서버가 주는 응답이 갖는 상태코드)
    맨 앞자리 숫자에 따라 종류가 정해짐


Axios

< 5강 >

  • Axios란?
    promise를 기초로 해서 http 통신을 할 수 있는 라이브러리

  • 설치

yarn add axios
yarn add json-server
  • root폴더에 db.json 파일 생성

  • async await를 코드 전체가 기다려주는게 아님 주의!
    async await 있어도 코드는 위에서 아래로 실행되기에, jsx부분이 먼저 실행될 수 있는 것임!
    -> optional chanining 넣어주면 됨 ?.
    ex) todos?.map((item)=>{})

📝 옵셔널 체이닝이 뭔데.....?

  • 값을 읽어서 처리해야하는 로직인 경우,
    원래는 값이 undefined 이면 오류가 나는데,
    ?. 옵셔널 체이닝을 사용하면 값이 undefined인 경우는 패스하고 넘김
    (오류로 로직이 멈추는 것을 방지해줌)

참고 : https://anywhereim.tistory.com/35

< 6강 >

  • 서버에 데이터 추가해줘 요청하기! POST
    json 방식의 데이터베이스는 id속성이 자동으로 입력됨
    -> 초기 dummy data시 id 키는 없어도 됨

  • form태그 안의 button
    form태그 안의 button type은 기본적으로 submit타입이 들어가 있음
    -> 버튼 클릭때마다 화면이 새로고침됨
    -> 막아주려면

<form
      onsubmit = {(e) => {
  		e.preventDefault();
  }}

클릭시 실행되는 로직은 onClick으로 하지 않고,
form 태그 안에 prevent부분 아래에 함수 넣어주기

axios로 request 보내기

  • axios로 요청할 때는 모두 async await로 감싸야 함!
    (서버와 통신 -> 어떤 동작을 실행하는 순서로 진행해야 하기에 비동기 통신)

  • 서버 가져오고싶어 요청하기 (GET) - 조회

const { data } = await axios.get("http://localhost:4001/todos");

  • 서버에 새로운 데이터 넣고싶어 (POST) - 삽입
axios.post("http://localhost:4001/todos", inputValue);
// inputValue - 새로 넣고 싶은 데이터

-> 서버에 데이터 넣음과 동시에 화면에서도 새로운 데이터로 렌더링 시키려면
-> POST로직 아래에서 state값도 같이 바꿔줘야함?!
(불변성 유지하면서)
-> 이렇게 하면 db에는 id가 자동으로 들어가지만, 렌더링할땐 id가 없이 나오는 오류
-> set으로 바꿔주지 말고 그냥 get으로 다시 db를 읽어오는 방식을 차용하자

  • 서버에 있는 특정 데이터를 삭제하고싶어 요청하기(DELETE) - 삭제
axios.delete(`http://localhost:4001/todos/${id}`);
setTodos(todos.filter((item)=>{
	return item.id !== id;})
// id : onClick 함수에서 인자로 받아온 id
// POST 했을 때 state도 같이 바꿔줬던 것처럼, DELETE때도 state 같이 바꿔줘야함

(주의! 안에 ${ } 있으면 쌍따옴표 아니고 백틱!)

  • 서버에 있는 데이터를 수정하고싶어 요청하기 (PATCH) - 수정
const onUpdateButtonClickHandler = async () => {
	axios.patch(`http://localhost:4001/todos/${targetId}`, {
    	title: contents,
    })
  
  	setTodos(todos.map((item) => {
    	if (item.id == targetId) {  // 형이 다른 경우 '==' 동등연산자 사용
        	return { ...item, title: contents }
        } else {
        	return item;
        }
    })
}

// 필요한 값은 state로 관리중이라 함수 인자로 안넣어도 됨
// targetId : state임, onChange에서 받아온 값
// patch의 두번째 인자 : 이거로 수정해주세요
// contents : state임, onChange에서 받아온 값

< 7강 >

  • fetch : axios와 같은 역할
    js 내장 라이브러리
    (axios는 설치해야되는 패키지)

  • 단점
    미지원 브라우저 있음
    response가 불친절


Axios Interceptor

< 8강 >

axios interceptor

중간에서 가로챔
요청, 응답 사이에 가로채서 어떤걸 한다!

axios interceptor 사용방법

  1. root 폴더에 .env 파일 생성 (환경정보 파일)
    -> github에 막 올리면 안됨 (민감정보)
    -> 변수명을 프로젝트 전반에서 사용 가능!
// .env
// (환경변수)
REACT_APP_SERVER_URL=http://localhost:4000
// 앞에 REACT_APP_ 이 부분은 꼭 있어야 함!
  • 컴포넌트 안에서 사용할때 예시
axios.delete(`${process.env.REACT_APP_SERVER_URL}/todos/${id}`)

(이렇게 변경해준 후에는 서버 한번 껐다 켜야됨)

  • 코드상에서 기존에 작성해놓은 서버 url을 전부 수정해야할 경우,
    모두 수작업으로 바꿔주는건 너무 비효율 & 휴먼에러 확률 증가
    -> 서버 주소를 전역에서 사용할 수 있는 변수로 만들어주자!
    -> .env 파일에서 변수로 지정해 그 변수를 전역에서 사용해보자

  1. axios폴더 생성, api.js 파일 생성, axios instance 만들기
  • axios.get, axios.post 등 : 가공하지 않은, Interceptor처리 안한 순수한 axios instance 이용해서 api요청해왔음
    -> 내맘대로 가공해서 사용하려고 만드는게 axios interceptor
const instance = axios.create({
	baseURL: process.env.REACT_APP_SERVER_URL,
})

export default instance;

=> axios import 필요없이,

  • api파일을 import해서 axios대신 api라고 다 바꿔주기
  • ${process.env.변수} 부분을 지우고 남은 주소만 "/todos" 이런식로 그냥 적으면 됨

  1. 가공한 instance를 interceptor 이용해서 요청-응답 사이에 관여해보자
// ✅ api.js

// ⭐️ 요청 부분(request)
instance.interceptors.request.use(

  // 요청을 보내기 전 수행되는 함수
  function(config){
  	console.log('인터셉터 요청 성공')
    return config;
  },
  
  // 오류 요청을 보내기 전 수행되는 함수
  function(error){
  	console.log('인터셉터 요청 오류');
    return Promise.reject(error);
  },
)

// ⭐️ 응답 부분(response)
instance.interceptors.response.use(

  // 응답을 내보내기 전 수행되는 함수
  function(reponse){
  	console.log('인터셉터 응답 받음')
    return response;
  },
  
  // 오류 응답을 내보내기 전 수행되는 함수
  function(error){
  	console.log('인터셉터 응답 오류 발생');
    return Promise.reject(error);
  },
  
)

Redux thunk

< 9강 >

Redux 미들웨어

(가장 많이 사용되는 Redux 미들웨어 : Redux-thunk, saga)

  • 미들웨어란 : 액션 -> 리듀서 사이에 내가 원하는 작업도 끼워넣을수 있게 해줌

  • 서버와 통신할때 주로 사용함


thunk

  • redux 미들웨어 중 가장 많이 사용되는 미들웨어 중 하나!

  • dispatch에 액션 객체가 아닌, 함수를 전달할 수 있다!!
    -> 이 함수를 통해 중간에 하고자 하는 작업을 넣을 수 있음
    -> 이 함수가 바로 thunk 함수

  • thunk함수도 서버와 통신하는 함수이기 때문에 async, await


사용방법

  1. thunk 함수 만들기 : createAsyncThunk() (reduxToolkit 내장 API)
  • 2개의 인자
    • 이름 : 큰뜻없음
    • 함수(중간에 실행할 거 넣을 함수) : 얘도 2개 인자를 받음
      • payload : 컴포넌트에서 보내준 payload
      • thunkAPI : thunk의 내장 기능 갖고 있는 객체
      • 함수 안에는 수행할 동작을 넣는데, thunk.dispatch(action creator(payload))로 전달함
  1. creatSlice 안에 있는 extraReducer 수정 (thunk 등록)
  2. dispatch (인자는 함수 0 액션 객체 x)

custom hooks

< 11강 >

custom hooks

  • 반복되는 로직, 중복되는 코드들을 나만의 hook으로 관리할 수 있게 해줌!
  • 사용방법
    src > hooks 폴더 생성
    useInput.js(임의 이름) 파일 생성

⭐️ 구조분해할당으로 const [ name, onChangeHandler ] = useInput();
이렇게 쓰는거야..? 인자로 넣는게 아닌데 어떻게 이게 useInput으로 사용할수 있게 되는거야...? ⭐️


React Query

< 12강 >

React Query

  • thunk 한계를 개선할 수 있는 대체재

  • 기존 미들웨어의 한계
    보일러 플레이트 -> 쳐야되는 코드가 너무 많아
    리덕스가 비동기 데이터 관리를 위한 전문 라이브러리가 아님!

  • 리액트 쿼리 장점
    사용이 쉬움
    보일러 플레이트 만들다가 오류날 일이 없음

  • 주요 키워드

  1. Query : 문의, 의문(물어보는거 -> ex. axios의 get)
  2. Mutation : 변경(어떤 데이터를 변경하는 것) -> 추가, 수정, 삭제
  3. Query Invalidation : 무효화
    서버에서 데이터의 변경이 일어났어도 내 화면에는 기존에 가져온 쿼리만 보임
    (최신 상태가 아닐 수 있다는 뜻)
    -> 기존 쿼리를 무효화시키고, 최신화 해야 함
    -> 리액트 쿼리가 알아서 해줌! (Query Invalidation)
  • 사용법
  1. axios, json-server, react-query

  2. db.json 파일 생성

  3. root 파일에서 <QueryClientProvider client={queryClient}><Router>감싸주기

  4. api폴더 생성 > todos.js
    (axios 요청이 들어가는 모든 모듈 모아놓기)
    useQuery(); : usequery 호출하기

  • 인자 2가지 : 쿼리의 이름, import해온 api
  • 예시 : const { isLoading, isError, data } = useQuery("todos", getTodos);
    (getTodos : todos.js파일에서 생성한 데이터 조회 api)

throttling & debouncing

< 14강 >

throttling & debouncing

  • 짧은시간 연속적인 이벤트 발생할때, 과도한 이벤트 핸들러 호출을 방지하는 기법

  • throttling : 몇초동안 이벤트 안받아요~! (몇 초 후에는 실행시켜줌)
    이벤트가 빠르게 연속적으로 발생하는 경우 delay기간을 주기
    (delay시킨 다음 이벤트 발생시켜도 되고, 이벤트 발생 후 delay줘도 되는 등 3가지 타입이 있음)
    Ex) 무한스크롤

  • Debouncing : 여러번 누르는동안은 실행 안시켜줘(마지막꺼 실행해줄게)
    짧게 여러번 이벤트 발생할때 마지막 이벤트로부터 일정기간 지난 후에 한번만 이벤트 발생하게 해주는 것

  • 메모리 누수
    throttling적용시, 다른페이지로 이동했는데도 아직도 혼자 delay 되다가 '이제 실행됩니다' 하는거 -> 다른페이지 왔으면 어쨌든 실행 끝나야지 아직도 영향 주고있는거 -> 메모리 누수

  • 메모리 누수 막는 방법 : useEffect의 return문

useEffect(()=>{

return ()=>{
	// 언마운트 시 로직 실행! (ex. 페이지 이동시(=언마운트시) 타이머 초기화하기)
	};
})

Lodash

< 15강 >

  • Lodash : debouncing, throttling 관련 라이브러리
  • lodash 설치 후 _로 import
    ex)
const handleSearchText = _.debounce(함수, ms초);

-> useCallback으로 감싸야함!

⭐️ 클로저 함수가 뭐였더라..? ㅠ ⭐️


인증/인가

< 16강 >

인증/인가

  • 인증(Authenticaton) : 등록된 회원인지 확인하기(로그인)
  • 인가(Authorization) : 권한이 있는지 확인하기(카페 권한있는 레벨인지?, 카페장인지?, 마이페이지에 권한이 있는지 등)

http 프로토콜 통신의 특징 2가지

  1. 무상태 Stateless
  • 서버는 클라이언트의 상태를 기억하지 않음
    -> 요청할때마다 서버에 요구하는 모든 상태 모아서 보내야됨
    (매번 새로운 요청인것임)
  1. 비연결성 Connectionless
  • 요청 - 응답 -> 끝
    최소한의 서버 자원으로 서버 유지 가능
    <-> 연결성 : 카톡 채팅(계속 연결돼있어서 계속 실시간으로 통신이 됨)
  • 쿠키 : 무상태, 비연결성임에도, 서버가 클라이언트 인증 상태 기억하는것 처럼 구현하는 것

세션 session

< 17강 >

세션 session

  • 클라이언트 - 서버 연결이 활성화된 상태를 의미함
    (인증이 유지되고있는 상태)
    ex) 로그인 성공 -> 서버에서 세션 생성, 저장 -> 세션 key를 쿠키를 통해 브라우저에게 전달
  • 서버에서 보관하는 정보(session key)

토큰, JWT(Json Web Token)

< 18강 > 🍀🍀 중요

토큰(token)

  • 클라이언트에서 보관하는 '암호화된 인증 정보'
  • 클라이언트에서 보관하는 정보 -> 서버부담 줄여줌
  • 웹에서 인증 수단으로 사용되는 토큰은 주로 JWT를 이용

JWT 특징

  • header.payload.signature 형식으로 3가지 데이터로 구성됨
// 예시
Set-Cookies: access Token=header.payload.signature; Path=/
  • 국제 인터넷 표준 인증 규격 중 하나

인증 과정(authentication)

  • 로그인 클릭(id,pw 가지고 POST 요청)
    -> 서버에서 DB에 이사람 존재하는지 확인
    -> 존재하면 memberData 객체를 서버에게 줌
    -> 존재하는 유저인 경우 Secret Key에 의해서 JWT토큰을 발급 (서버가)
    (JWT토큰 발급시 사용하는 API를 사용할때는 항상 Secret Key 넣게 되어 있음)
    (secret key 코드는 보안상 비밀이 유지되어야 함!)
    -> 발급한 JWT토큰을 클라이언트에게 Response로 전달
    (전달 방법 2가지 : 쿠키에 전달 or body에 전달)
    (쿠키에 전달했으면 브라우저에 자동으로 삽입되어 있을 것)

인가 과정(authorization)

  • product-list 요청하기(GET)
    -> JWT토큰 가지고 서버에 요청
    -> 서버에서 토큰이 유효한가 검증
    -> 토큰이 유효하면 요청받은 정보를 DB에서 가져옴
    -> 클라이언트에게 reponse로 전달
profile
무서운 속도로 흡수하는 스폰지 개발자 🧽

0개의 댓글