240610 ~ 240614 프로젝트 종료!
회고록은 어제 썼다~!
전역 상태 관리
yarn add zustand
//beatsStore.js create 임포트 필요
//화살표 함수 예제
const @@BeatsStore = create((set) => ({
bears: 0,
increase: () => set((state) => ({
bears: state.bears + 1
})),
init: () => set({
bears: 0
})
}));
//beatsStore.js create 임포트 필요
//함수 표현식 예제
const @@BeatsStore = create(function(set) {
return {
bears: 0,
increase: function() {
set(function(state) {
return {
bears: state.bears + 1
};
});
},
init: function() {
set({
bears: 0
});
}
};
});
const {bears} = useBearsStore((state)=>state)
const increase = useBearsStore((state)=>state.increase)
const {bears, increase, init} = useBearsStore((state)=>state)
이렇게도 쓸 수 있다~
immer 라이브러리가 안 깔려있다.
불변성을 어기는 행위 (= 직접 객체나 배열을 수정하여 값이 "변하는" 행위)
1. 배열에 그대로 푸시
2. 객체를 그대로 수정
인간 관점으로는 객체, 배열이 변했지만 쥬스탠드(=컴퓨터)는 이와 같은 행동은 값 변경을 인지하지 못한다. 컴퓨터는 얘가 변하든지 말든지 똑같은 주소에 참조되어있으니까 상관하지 않는다~!
+) 리액트에서 불변성 (= 변하지 않음) 을 유지
불변성을 유지한다. 화면이 바뀐다.
이 사이에는 연결 고리가 있다.
컴퓨터에게 얘 달라졌어요 하고 신호를 줘야 한다.
변하지 않음을 유지하되, 화면을 바뀌게 하기 위해서는 주소값을 다르게 할 필요가 있다. => 그래서 새로운 객체 배열을 복사 (=주소 값 다르게) 해서 사용하는 것.
불변성 유지라고는 하지만 실제로는 복사하고 주소값 바뀌고 한다...
yarn add immer
//@@store.js
import create from 'zustand'
import { immer } from 'zustand/middleware/immer';
const @@BeatsStore = create(immer((set) => ({
bears: 0,
increase: () => set((state) => ({
//불변성 어기는 예시 어쩌고 직접 푸쉬
})),
init: () => set({
//불변성 어기는 예시 어쩌고 객체 속성 직접 수정
})
})));
zustand?
장점 빠르고 설정이 쉽다
단점 상태가 커지면 관리하기 어렵다
RTK?
장점 대규모 어플 관리 가능
단점 설정이 복잡하다.
새로고침하면 사라짐!
그래서, 로컬 스토리지, 세션 스토리지 이용하여 저장해야 할 경우
//@@store.js
import create from 'zustand'
import { immer } from 'zustand/middleware/immer';
import {persist } from 'zustand/middleware'
const @@BeatsStore = create(persist(immer((set) => ({
bears: 0,
increase: () => set((state) => ({
//불변성 어기는 예시 어쩌고 직접 푸쉬
})),
init: () => set({
//불변성 어기는 예시 어쩌고 객체 속성 직접 수정
})),
{
name : "어쩌고이름"
// getStorage: () => sesstionStorage 세션에서 저장하고 싶을시
}
})));
? 연속해서 발생한 이벤트를 일정 시간 단위로 그룹하여 처음 혹은 마지막 이벤트 핸들러만 호출 (*10초에 12903109328119번 눌러도 시간에 따라 몇 번만 되게 한다.)
주로 무한 스크롤에서 사용됨
Leading Edge
? 이벤트가 처음 발생한 후 주어진 시간 동안은 이벤트가 무시된다.
e.g.스크롤을 시작할 때 API 호출, 일정 시간동안 추가 호출을 무시
↕️ 반대 개념! ↕️
Trailing Edge
? 이벤트가 반복적으로 실행될 때, 주어진 시간이 지나면 마지막 이벤트를 처리한다.
e.g. 입력 필드에 타이핑을 멈춘 후 일정 시간이 지나야 서버에 검색 요청이 전송
= 합친 개념!
Leading & Trailing Edge
? 주어진 시간에 대해 이벤트가 처음 발생할 때 핸들러 실행, 주어진 시간이 지나면 마지막 이벤트도 처리
e.g. 버튼을 여러번 클릭했을 때, 최초에 api 호출 + 주어진 시간의 마지막 이벤트에도 api 호출
? 짧은 시간 간격으로 연속해서 이벤트가 발생하면 이벤트 핸들러를 호출하지 않다가, 마지막 이벤트로부터 일정 시간이 경과한 후 한 번만 호출
e.g 입력값 실시간 검색, 화면 resize 이벤트
throttling, debouncing은 setTimeout을 주로 사용한다. 이 함수로 인하여 메모리 누수 가능성이 있긴 하다!
함수가 끝나기 전에 다른 페이지로 이동한다면 메모리 누수 관련 처리를 해줘야 한다!
useEffect + 클린업 함수를 사용하기
e.g.
useEffect(()=> {
return () => {
if (@@) {
clearTimeout(@@)
}
}
})
? 유틸리티 라이브러리로, 배열, 객체, 문자열 등 데이터 조작을 쉽게 할 수 있는 다양한 함수를 제공!
=> throttle, debounce 함수도 포함
yarn add lodash
import _ form "lodash"
_.throttle(()=> 로직, 시간)
_.debounce(()=> 로직, 시간)
classname= "여기서 바로 쓰는 거"
마음에 든다 짱이다!!
yarn add tailwindcss postcss autoprefixer
npx tailwindcss init -p
//tailwind.config
module.exports = {
content: [
'./index.html',
'./src/**/*.{js,jsx,ts,tsx}',
],
theme: {
extend: {},
},
plugins: [],
}
//index.css
@tailwind base;
@tailwind components;
@tailwind utilities;
이제 한 번 껐다 키고, (*config 설정 했으므로)
이제 스타일 주고 싶은 곳에 가서!!
e.g.
<div className="flex justify-between items-center"> 안녕</div>
얼른 익숙해지기로 한다.
? 다양한 기기에서 인터넷을 할 때 화면이 자동으로 편안하게 바뀌는 것
사이트를 만들 때 모든 디바이스에 대응하는 사이트를 따로 만들지 않아도 된다.
e.g.
.container {
padding : 20px;
}
@media (max-width:768px) {
.container {
padding : 10px;
}
}
=> 너비 768px 까지는 패딩은 10px만...
e.g.
const container = styled.div`
padding :20px;
@media (max-width:768px) {
padding : 10px;
}
`
e.g
// SampleComponent.jsx
import React from 'react';
import { useMediaQuery } from 'react-responsive';
const SampleComponent = () => {
const isMobile = useMediaQuery({ query: '(max-width: 768px)' });
return (
<div style={{ padding: isMobile ? '10px' : '20px' }}>
반응형 웹
</div>
);
}
export default SampleComponent;
e.g 예제
/** @type {import('tailwindcss').Config} */
module.exports = {
theme: {
screens: {
'sm': '640px',
// => @media (min-width: 640px) { ... }
'md': '768px',
// => @media (min-width: 768px) { ... }
'lg': '1024px',
// => @media (min-width: 1024px) { ... }
'xl': '1280px',
// => @media (min-width: 1280px) { ... }
'2xl': '1536px',
// => @media (min-width: 1536px) { ... }
}
}
}
하단의 주석과 같은 뜻임!
실제 적용
e.g.
<div>
<span className="block md:hidden lg:hidden">모바일 환경</span>
<span className="hidden md:block lg:hidden">테블릿 환경</span>
<span className="hidden lg:block">데스크탑 환경</span>
</div>
? 미리 정해진 화면 크기에 맞게 웹사이트를 만드는 것
각 기기마다 디자인을 다르게 만들 수 있음
오늘 잡은 버그에 대해서 몇 가지
user 정보 관리
마이페이지에서 프로필 사진 수정 안 하고 닉네임만 수정했을 때 프로필 사진이 날라가고 디폴트 이미지로 업데이트
=> 리덕스 세팅 다시 해줌
글리치 서버 오류
무한 로딩에 걸림
패치에도 안 뜸
이유? 테스트용으로 몇 개 넣어놨는데 삭제하다가 ] 와 , 등등 빼먹었다! 서버 로그도 잘 확인하기~!
마이페이지에서 새로 고침 시 오류
초기 유저 세팅이 null일 경우 불러오지 못하는 거라 useEffect로 다시 초기 세팅
useEffect(() => {
if (!isAuthenticated) {
Swal.fire({
title: "로그인 후에 이용해주세요.",
text: "로그인 페이지로 이동합니다.",
});
navigate("/login");
} else {
if (user) {
dispatch(setUser(user));
}
}
}, [isAuthenticated, dispatch]);
+)
TODO 하고 싶은 거
1. 버셀 배포 페이지에서 새로 고침 하면 안 되는 오류
2. 페이지 나가면 자동으로 로그아웃되는 기능
3. 토큰 만료 되면 로그아웃 되게 설정
4. 랜더링 늦어서 user 정보 안 나오는 거 이유 찾기
5. 마이페이지에서 사진 안 바꾸면 기본 이미지 됐다가 -> 새로 고침하면 다시 원래 이미지로 바뀌는 이유 ?

빈 배열이다가 갑자기 됨... 후...^^ 느리잖아요
+ 이전 유저 정보 남아있음~~

근데 굉장히 힘들었나보다! 😂
수정 후
useEffect(() => {
const getUserInfo = async () => {
const token = localStorage.getItem("accessToken");
if (token) {
try {
const { data } = await axios.get(
"https://moneyfulpublicpolicy.co.kr/user",
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);
dispatch(setUser(data));
} catch (error) {
console.log(error);
}
}
};
getUserInfo();
}, [dispatch, token]);
유저 정보 담는 부분에 의존성 배열에 token 추가 하니까 됐다~!

새벽 1시 50분.......... 오류 고치기 좋은 시간^-^~! 뭔가뭔가 하나만 고치고 가려다가 시간이 생각보다 더 흘러가버렸다. 허리가 뽀개질 거 같다
(과제 제출 후)

배포하고 문제 생겨서 와다다다다 커밋 푸쉬했다. 근데 잡고 나니 즐겁다^-^ 그래서 룰루랄라 기능 하나 더 넣었다. 오류... 🥹 는 안 났다... 다행...