๋ฌธ์ ์์์ ๋ค์ด๊ฐ ์์ด์ฝ์ ๋ฃ์ด์ฃผ๊ธฐ ์ํด ๋ค์๊ณผ ๊ฐ์ด ๊ธฐ์กด์ png๋ jpg ํ์ผ์ importํ๋ ๋ฐฉ์์ผ๋ก svg ๋ฆฌ์์ค๋ฅผ ๊ฐ์ ธ์๋ค. import linkBtnImg from '../../../assets/icon-link_to_button.svg'; ํ์ง๋ง ์ด๋ฐ ์์ผ๋ก ์ฌ์ฉํ๋ค ๋ณด๋, ํฌ๊ธฐ๋ง ๋ค๋ฅธ svg๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์ ๋๊ฐ์ ๋ฆฌ์์ค๋ฅผ ๋ ๋ฒ import ํด์ผ ๋๋ ๋ฒ๊ฑฐ๋ก์ด ๋ฌธ์ ๊ฐ ์์๋ค. ๋ฌธ์ ํด๊ฒฐ ์์ ๋ฐฉ์์ด ์๋ svg ์์ฒด๋ฅผ ์ปดํฌ๋ํธํ ์ํค๋ ๋ฐฉ์์ ์ฌ์ฉํ๊ธฐ๋ก ํ์๋ค. ์ฐ์ ๋ค์๊ณผ ๊ฐ์ด ํด๋น svg ํ์ผ์ ReactComponent์ ํํ๋ก import ํด ์จ๋ค. import { ReactComponent as LinkToButton } from '../../../assets/icon-lin..
๋ฌธ์ ์ํฐ๋ ํ๋ฆฌ์จ ๋ณด๋ฉ ์ ๋ณ ๊ณผ์ ์์ Nav๋ฅผ ์ ์ํ๋ ์ค, ๋ ์ด์์ ๊ตฌ์ฑ ๋ชฉ์ ์ผ๋ก flex ๊ด๋ จ ์์ฑ๋ค์ ๊ณ์ ์ฌ์ฉํ๋ ๊ฒ์ ํ์ธํ ์ ์์๋ค. ๋์์ธ์ ์ ์ฉํ๋ ๊ฒ์ ์์ด์ ๋ฌธ์ ๋ ์์ง๋ง ๋ฐ๋ณต๋๋ ์ฝ๋๋ฅผ ์ค์ฌ ์คํ์ผ์ ์ ์ฉํ ์ ์๋์ง ๊ณ ๋ฏผํ๊ฒ ๋์๊ณ scss์์ variable์ ๋ณ๋๋ก ๋ถ๋ฆฌํ์ฌ ๊ณตํต ์คํ์ผ ์์ฑ์ ์ ์ํ๋ ๊ฒ๊ณผ ๊ฐ์ด styled-components์์ ์ฌ์ฉํ ๋ณ์ ๋ชจ์ ๊ฐ์ฒด์ธ theme์ ์ด์ฉํ์ฌ flex ๊ด๋ จ minin ํจ์๋ฅผ ์ฌ์ฉํด ๋ณด๊ธฐ๋ก ํ์๋ค. Code themeProvider๋ก ์ ์ญ ๋ณ์๋ก ์ฌ์ฉ๋๋ theme ๋ด๋ถ์ flex ์์ฑ์์ ์์ฃผ ์ฌ์ฉ๋๋ mixin ์์ฑ์ ํจ์ ํํ๋ก ๋ค์๊ณผ ๊ฐ์ด ์ ์ํ์๋ค. const theme = { flexMinin: (direction ..
Issue ํ์ฌ ํ๋ก์ ํธ ๋์ค, ์ฌ์ฉ์์ ์ธ์ฆ/์ธ๊ฐ๋ฅผ ํตํด ์๋น์ค๋ฅผ ๊ตฌ์ถํ๊ธฐ ์ํด ์๋ฒ๋ก๋ถํฐ ๋ฐ๊ธ ๋ฐ์ JWT ํ ํฐ์ ์ด๋์ ์ ์ฅํด์ผ ๋ ์ง ๋ง์ ๊ณ ๋ฏผ์ด ์์๋ค. ์ฒ์์๋ store์ ๋ฐ๊ธ ๋ฐ์ JWT ํ ํฐ์ ์ ์ฅํด์ฃผ๋ ๋ฐฉ์์ผ๋ก ์งํํ์๋๋ฐ, JWT ํ ํฐ์ด ํ์ํ ์ํฉ๋ง๋ค ๋งค๋ฒ store์ ์ ์ฅ๋์ด ์๋ ๊ฐ์ useSelector()๋ฅผ ํตํด ๊ฐ์ ธ์ค๋ ๊ฒ์ ์ ์ฒด ์ฝ๋๋ฅผ ๋ฒ์กํ๊ฒ ๋ง๋๋ ๋ฌธ์ ๊ฐ ์์๋ค. ๋ณด์์์ ์ด์๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด ๋ฐฑ์๋ ์ธก๊ณผ ์ํตํ์ฌ refresh token์ ์ฌ์ฉํ๋ ๋ฐฉ์์ด ๊ฐ์ฅ ์ข์๊ฒ ์ง๋ง ๋น์ ๋ฐฑ์๋ ๊ฐ๋ฐ์์ ์ํฉ์ด ์ฌ์์น ์์๊ธฐ ๋๋ฌธ์ ํด๋ผ์ด์ธํธ ์ธก์์ ํ ์ ์๋ ์ต์ ์ ๋ฐฉ๋ฒ์ ์ ํํ๊ธฐ๋ก ํ์๋ค. ์ด์ ๋ฐ๊ธ ๋ฐ์ JWT ํ ํฐ์ localstorage์ ์ ์ฅํ๋ ๋ฐฉ์์ ํ๋ก์ ํธ์ ์ ๋ชฉ..
๋ฌธ์ ์๋ฒ์์ API ํต์ ๋์ค ๋น๋๊ธฐ์ ์ฒ๋ฆฌ์ ์ธ์๊ณผ ์ ์ด๋ฅผ ํจ์จ์ ์ผ๋ก ํ๊ธฐ ์ํด ๋ค์๊ณผ ๊ฐ์ด redux-saga ๋ฏธ๋ค์จ์ด๋ฅผ ์ด์ฉํ ์ ํธ ํจ์๋ฅผ ๋ง๋ค์๋ค. export const createRequestActionTypes = type => { const SUCCESS = `${type}_SUCCESS`; const FAILURE = `${type}_FAILURE`; return [type, SUCCESS, FAILURE]; }; export default function createRequestSaga(type, request) { const SUCCESS = `${type}_SUCCESS`; const FAILURE = `${type}_FAILURE`; return function* (action)..
๋ฌธ์ ํน์ ํ์ด์ง์ ๋ค์ด๊ฐ์ ๊ฒฝ์ฐ, ์กฐ๊ฑด๋ถ ๋๋๋ง์ ํด์ฃผ๊ธฐ ์ํด์ react-router-dom ๋ด matchPath()๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์๊ณผ ๊ฐ์ด ์ฝ๋๋ฅผ ์์ฑํ ๊ฒฝํ์ด ์์๋ค. const TopNav = () => { const navigate = useNavigate(); const location = useLocation(); const isAuthView = () => { const currentPathname = location.pathname; if ( matchPath(currentPathname, { path: "/login" }) || matchPath(currentPathname, { path: "/login" }) ) return true; else return false; }; if (..
Issue https://swiperjs.com/react Swiper React Components Swiper is the most modern free mobile touch slider with hardware accelerated transitions and amazing native behavior. swiperjs.com ํ์ฌ ํ๋ก์ ํธ์์ ์ฌ์ฉ์์๊ฒ ํ๋ก์ฐํ ๋งํ ์น๊ตฌ๋ฅผ ์๋จ ๋ฐ์์ ๋ณด์ฌ์ฃผ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค. ์ด๋ ์น๊ตฌ ๋ฆฌ์คํธ๋ฅผ ํ ๋ฒ์ ๋ชจ๋ ๋ณด์ฌ์ฃผ๋ ๊ฒ์ด ์๋๋ผ ์ด๊ธฐ์ 8๋ช ์ Friend Figure๋ง ๋ณด์ฌ์ฃผ๊ณ ์ฌ์ฉ์๊ฐ ๋ฒํผ์ ํด๋ฆญํ์์ ๊ฒฝ์ฐ์ ํํด์, 8๊ฐ์ ๋ฐฐ์๋ก ์ ๋์ ์ผ๋ก ์ฆ๊ฐํ๋ offset์ query๊ฐ์ผ๋ก ์ค์ ํ์ฌ ์๋ฒ์ API ํต์ ์ ํ๋ค. Carousel Slider ๊ธฐ๋ฅ์ ..
Issue ํ๋ก์ ํธ ๋์ค ํ์ ๊ฐ์ ์ฐฝ์ด ๋จ๊ธฐ ์ ์ ์ด์ฉ ์ฝ๊ด ๋์ ์ฐฝ์ ๋ํ ๋์์ธ ์์์ด ์ถ๊ฐ๋์๋ค. ์ฒ์์๋ ์ด์ฉ ์ฝ๊ด ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ ค๊ณ ํ์ง๋ง, ์ฒดํฌ ๋ฐ์ค ๊ด๋ จ ๊ธฐ๋ฅ์ ์์ผ๋ก๋ ๋ง์ด ์ฐ์ผ ์ ์๊ธฐ ๋๋ฌธ์ ์ด๋ฒ ๊ธฐํ์ ์ค์ค๋ก ๋ฌธ์ ๋ฅผ ํด๊ฒฐํด๋ณด๊ธฐ๋ก ํ์๋ค. Code ์ฐ์ , ๊ฐ ์ฒดํฌ ๋ฐ์ค์ ์ฒดํฌ ํ์ฑ์ ๋ํ ์ฌ๋ถ๋ฅผ ์ ์ฅํด์ฃผ์ด์ผ ์ด์ฉ ์ฝ๊ด ๋์ ์ฐฝ์์ ์ฌ๋ฌ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์๊ธฐ ๋๋ฌธ์ ๋ค์๊ณผ ๊ฐ์ด ๊ฐ ์ฒดํฌ ๋ฐ์ค์ Key๊ฐ์ ๋ํ ์ฒดํฌ ์ฌ๋ถ๋ฅผ ํ์ธํ ์ ์๋ Boolean Value๋ฅผ ์ง๋ ๊ฐ์ฒด๋ฅผ state๊ฐ์ผ๋ก ์ด๊ธฐํ ํ์๋ค. const [checkInfo, setCheckInfo] = useState({ webAccessCheck: false, privateInfoCheck: false, a..
Issue ํ์ฌ ํ๋ก์ ํธ์์ ๋๋ถ๋ถ์ ์ฌ์ด๋ ์ด๋ฒคํธ์ ๋ํ ๋ด์ฉ์ Modal ์ฐฝ์ด ๋์์ ธ ํ๋ฉด์ ๋๋๋ง๋๋ค. ์ด๋ฅผ ์ํด Modal ์ฐฝ์ ๋ํ Presentation Component์ธ BodyBlackout ์ฝ๋๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ์์ฑํ์๋ค. mport { useDispatch } from "react-redux"; import styled from "styled-components"; const BodyBlackout = ({ modalSort, setAuthModalVisible, isVisibleAuthModal, }) => { const dispatch = useDispatch(); if (isVisibleAuthModal) document.querySelector("body").style.setPr..