일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 부트캠프 #스파르타코딩클럽 #개발일지# #TIL #Javascript #confirm #location.href
- 특성선택자
- 부트캠프 #코딩 #개발일지 #프론트엔드 #CSS #TIL
- 부트캠프 #CSS #개발일지 #TIL #박스모델
- CSS
- JS예제
- 부트캠프 #개발일지 #TIL #그리드 #CSS
- 결합선택자
- 알고리즘
- 리액트
- 부트캠프 #스파르타코딩클럽 #개발일지# #html
- 의사클래스
- js
- React
- querySelector
- 부트캠프 #CSS #개발일지 #TIL
- Til
- 템플릿스트링
- useState
- 부트캠프 #개발일지 #TIL #CSS속성 #float #clear
- 개발일지 #TIL #프론트엔드 #HTML
- 부트캠프 #개발일지 #TIL #FlexboxFroggy #displayflex #flexbox
- 부트캠프 #개발일지 #TIL #Position #위치
- appendChild
- useEffect
- 개발일지
- 부트캠프
- ㅜㄹㄹ
- textContent
- 깃허브오류
- Today
- Total
목록Programming (156)
나의 개발일지
MPA (Multi Page Application) 여러 페이지로 구성된 웹 애플리케이션이다. 전통적인 방식으로 jsp, php 등이 MPA 방식을 사용한다. 페이지 이동 시 서버로부터 HTML 파일을 전달받아 다시 렌더링을 하기 때문에 새로고침이 발생하고 이는 깜빡임이 나타나는 원인이 된다. 그렇기 때문에 페이지를 로드하는데 오래 걸리고 새로고침으로 인해 스크롤 위치, form, 포커스 등이 사라져서 사용자 경험에도 만족을 줄 수 없다. 반면, MPA는 SPA에 비해 SEO(검색 엔진 최적화)에 유리하다. 여러 페이지로 구성되어 있기 때문에 각각 키워드에 맞춰 meta tag를 추가할 수 있기 때문이다. meta tag는 웹페이지의 내용을 요약하는 기능을 하며, 이는 검색 엔진 페이지의 정보를 쉽게 이..
💡GitHub : https://github.com/hyeomin/final-project 💡Mango : https://www.mymango.today/ Keep 원활하고 적극적인 의사소통 자유롭게 의견을 말할 수 있는 분위기 상대방을 존중하는 말투 팀 노션을 활용하여 사소한 것이라도 메모 코드 컨벤션을 잘 지킨 것 commit msg를 가독성 있게 작성하고 자주 commit한 것 merge 상황 공유하고 conflict 방지를 위해 다 같이 merge 한 것 필수 기능 모두 구현한 것 github의 projects를 잘 이용한 것 각각의 기능의 유효성 검사 Problem 페이지 로딩시간 개선 firebase-backend 오류 react devtools를 적극적으로 활용 Try 시간이 더 여유로웠다면..
로딩 속도 개선을 위해 폰트 최적화가 필요했다 그러기 위해선 파일 용량 크기를 줄이거나 preload를 통해 성능을 개선하는 방법이 있다 1. otf , ttf 대신 woff2 파일 사용하기 & subset 폰트로 바꾸기 기존에 쓰고 있던 OTF 파일을 용량이 적은 WOFF2로 대체하면서 subset 폰트로 바꾸어 주는 사이트가 있다 https://transfonter.org/ Online @font-face generator The @font-face CSS rule allows web developers to specify online fonts to display text on their web pages. By allowing authors to provide their own fonts, @fo..
스켈레톤은 최종 프로젝트를 진행하며 처음 알게 되었다. 일상 속에서 그동안 많은 스켈레톤을 접했지만, 이것이 가져다주는 효과에 대해서는 생각해보지 못했다 매일 매일 사용하는 인스타그램 앱에서도 스켈레톤을 확인할 수 있었다. 아는 만큼 보인다고.. 이제서야 발견했다 ... 그렇다면 스켈레톤에 대해 정확히 알아보자 스켈레톤 UI는 사용자 인터페이스(UI)를 개발할 때 사용되는 디자인 패턴 중 하나다. 이 패턴은 로딩 시간이 긴 웹 페이지나 앱에서 사용자에게 진행 상태를 시각적으로 보여줄 수 있도록 도와준다. 스켈레톤 UI는 실제 내용이 아직 로드되지 않았을 때에도 사용자에게 페이지 구조와 레이아웃을 미리 보여주는 방식으로 작동한다. 이를 통해 사용자는 대기 시간 동안에도 인터페이스의 진행 상태를 알 수 있으..
모달이 뜨고 변경 전 프로필이 1초 정도 머물다가 바뀌는 오류가 있었다 기존 코드 const userProfileUpdateMutation = useMutation({ mutationFn: async ({ authCurrentUser, displayName, profileImage }: updateProfileInfoProps) => await updateProfileInfo({ authCurrentUser, displayName, profileImage }), onSuccess: (updatedUser) => { queryClient.invalidateQueries({ queryKey: [`${QUERY_KEYS.USERS}`] }); if (updatedUser) { authContext?.updat..
moment.js와 day.js는 둘 다 JavaScript에서 날짜 및 시간을 다루는 라이브러리다. 나는 moment.js를 통해 날짜를 받아왔다. 하지만 중간 피드백에서 튜터님이 moment.js보다 day.js를 사용하는 것이 좋다고 하여 리팩토링을 해봤다. 그렇다면 어떤 면에서 day.js가 moment.js보다 좋다고 할 수 있는지 알아보자. moment.js day.js 파일 크기 파일크기가 상당히 크다 62k (gzipped: 19.9k) --> 웹페이지 성능을 저하시킬 수 있다 moment.js에 비해 파일 크키가 작다 7.6k (gzipped: 3.2k) API 호환성 많은 개발자들이 익숙한 API를 제공하여 기존에 moment.js를 사용하던 프로젝트에서는 호환성을 유지하기 위해 mom..
반응형 구현 후, 모바일로 이것저것 보다가 구글 로그인을 시도했는데 오류가 발생하였다. 내가 mango 사이트를 들어간 경로는 카카오톡으로 링크를 공유하여 들어간 것이다. 403 오류 : disallowed_useragent 검색을 해봐도 해결을 해줄 수 있는 방법이 잘 나와있지 않았다. 어떤 블로그 말하길, 해당 브라우저(카카오톡)은 구글의 브라우저 정책을 준수하고 있지 않아서 로그인을 하지 못하니 다른 브라우저에서 시도해보라고 권하고 있다. 또한 보안 상의 이유로 웹뷰에서 구글 로그인을 차단하고 있다고 한다. 이를 해결하는 방법은 카카오 측에서 user-agent를 구글 측에서 허용하도록 하는 것인데 아직 해결이 안되었다고 한다. 다른 방법으로 시도하는 방법이 있다고는 했다. 하지만 그 방법은 우회하..
막막하기만 했던 반응형을 드디어 구현하게 되었다. 방법은 생각보다 간단했다 @media screen and (max-width: 431px) { } 라는 코드로 최대 넓이를 설정해주고 {} 안에 431px 미만일 때, 적용될 CSS를 쓰면된다. 만약 반응형 코드에 쓰지 않은 스타일이 있다면 원래 사용된 CSS로 적용이 된다. 즉, 431px 미만일 때, 이상하게 보여지는 CSS만 수정하면 되는 것 하다 보니, 반응형을 할 예정이면 무조건 같이 구현해야 한다는 것을 깨달았다. 처음부터 웹용으로만 만들다보니 잘 되지 않았다. 특히 스타일 컴포넌트를 구성하는 곳에서 어려움을 마주해야 했다 그래서 구조를 새롭게 짜거나 추가하는 경우가 꽤 있었다. 또한 다양한 넓이의 모바일이 존재했기 때문에 우리는 우선 아이폰 ..
마이페이지 내 게시물에서 게시물을 최신순으로 정렬하고 싶었다. 그래서 처음에는 쿼리 키로 데이터를 가져올 때, uid가 일치하는 것만 가져와서 오름차순으로 정렬을 했었다. 하지만 이 방법이 쿼리 키를 여러 번 호출하는 것 같아서 데이터를 한꺼번에 가져온 후 로컬 로직에서 가공하는 방법을 택했다. const getAllPosts = async () => { try { const postRef = collection(db, 'posts'); const querySnapshot = await getDocs(postRef); const posts: PostType[] = []; querySnapshot.forEach((doc) => { const postData = doc.data() as PostType; p..
다양한 query-key를 사용하고 있는데, 최적화를 위해 코드를 다시 살펴보았다. mypage에서 사용하는 것은 MyProfile.tsx에서 내 게시물 수, 유저랭킹 / HabitCalendar.tsx에서 날짜별로 게시물 수 / MyPosts.tsx에서 내 게시물 보여주기 / LikePosts.tsx에서 내가 누른 좋아요 게시물 보여주기가 있다. 하지만 Firebase에서 사용하는 컬렉션은 posts와 users 단 두 개 뿐이다. 데이터를 불러올 때, 여기저기 많이 사용해서 무분별하게 데이터를 많이 불러온다고 생각해서 전체 데이터를 우선적으로 가져온 뒤, 하나의 쿼리키를 사용하고 로컬 로직에서 가공하여 사용하면 어떨까를 생각했다. 하지만 분명 장단점이 있기에 정리를 해보면서 어떻게 사용해야 할지 생각..
검색 기능을 위해 Algoria 써보기로 했었다. (지금은 무산되었다.. 최적화가 우선순위였기에..) 그때 여러가지 firebase tools를 설치했었는데 그 이후로 밑의 사진과 같은 오류가 떴다 Firebase throws an error: "Could not reach Cloud Firestore backend. Backend didn't respond within 10 seconds." 정말 많은 여러 문서를 뒤져봤지만 명쾌한 답을 내려준 문서가 없었다.. 하지만 몇몇 문서에서 공통적으로 말하는 것이 있었다 experimentalForceLongPolling를 true로 설정하면 된다고 했다 https://www.youtube.com/watch?v=hJMubeJXkWc 이 영상에서도 똑같이 문제해..
피드백 1. 설정해놓은 비밀번호 정규식에 충족하지 않으면 에러 메세지가 뜨지 않았다. 해결방법 새로운 정규식 표현을 사용했다 기존 : /(?=.\d)(?=.[a-zA-ZS]).{8,}/; ( 8글자 이상 ) 수정 : /(?=.*\d)(?=.*[a-zA-ZS]).{1,}/; (영문자 1글자, 숫자 1글자 이상씩 입력해야함.) 피드백 2. 이메일 및 비밀번호가 틀릴 시에 처음 한 번은 뜨는데 두 번째, 세 번째는 modal창이 뜨지 않았다. 이유는 에러메세지가 바뀜에 따라 modal이 열리도록 구현하고, signIn 함수에서 에러가 발생했을 때, setErrorMsg를 호출하는 로직이 빠져있었다. 기존 코드 useEffect(() => { if (errorMsg) { const onClickSave = ()..
mypage에 탭들이 있는데 이런 탭을 클릭했을 때, 주소창의 내용이 더욱 직관적이게 보이고 링크 공유를 했을 시에 사용자가 원하는 탭이 공유가 될 수 있게끔 하기 위해선 QuertString이 필요했다 QueryString이란 URL의 끝에 위치한 데이터로, 웹 페이지나 애플리케이션에 정보를 전달하는 데 사용된다. 쿼리스트링은 ? 문자로 시작하고, 파라미터와 값의 쌍으로 구성됩니다. 각 파라미터와 값은 & 문자로 구분됩니다. https://heenee.tistory.com/manage/newpost/128?type=post&returnURL=https%3A%2F%2Fheenee.tistory.com%2F128 쿼리스트링을 구현하기 위해선 useLocation이라는 훅이 필요했다 const navigat..
웹폰트를 사용할 때 고려해야 할 점을 말씀해주세요. WOFF2 : 용량 적음 Pre-Loader : 미리 불러오기 제일 좋은 방법은 OS 시스템 폰트 사용하기 리액트 프래그먼트에 대해 아시나요? React.Fragment는 React의 컴포넌트 구조에서 매우 중요한 역할을 합니다. React에서는 컴포넌트를 반환할 때, 그 컴포넌트는 반드시 하나의 부모 요소로 감싸져야 합니다. 하지만 때로는 불필요한 div나 다른 HTML 요소로 감싸는 것이 원치 않을 때가 있습니다. 이럴 때 React.Fragment를 사용하면 됩니다. React.Fragment는 그룹화된 자식 요소들을 반환할 수 있게 해주지만, 실제 DOM에는 별도의 노드로 나타나지 않습니다. 따라서 불필요한 마크업 없이 여러 요소를 렌더링할 수 ..
중간 발표 후, 검색 기능이 꼭 필요하다고 느꼈다 main page에서 검색을 하면 searchPage로 이동하여 검색 결과를 보여줄 예정이다. 검색이라는 버튼을 누르면 searchPage로 이동을 해야 하는데 반짝하고 이동했다가 다시 돌아왔다. import React, { useState } from 'react'; import { collection, getDocs, query, where } from 'firebase/firestore'; import { db } from '../shared/firebase'; import { NavLink } from 'react-router-dom'; function Search() { const [searchTerm, setSearchTerm] = useSta..
로그인 시 이메일 또는 비밀번호가 틀릴 시 custom hook을 만들어 에러메세지를 modal창으로 띄워주려고 했다. import { useCallback, useState } from 'react'; const usePrintError = (error: any): [string, (error: any) => void] => { const [errMsg, setErrMsg] = useState(error); const printErr = useCallback((error: any) => { switch (error.code) { case 'auth/user-not-found': return setErrMsg('이메일이 일치하지 않습니다.'); case 'auth/wrong-password': retur..
어느덧 중간 발표까지 시간이 흘렀다! 항상 느끼지만 시간은 너무나도 빠르다. 나는 이번 중간 발표를 맡게 되었고 떨리는 심장을 부여잡고 잘 마무리하였다.. 많이 연습한 덕분이다 발표 후 튜터님의 피드백을 토대로 중간 발표 회고를 작성해보겠다 중간발표 피드백 기록 react-query 관심사 분리 좋음 package.json 중 dev dependency 필요한 거 분리해도 좋을 거 같음 뉴스룸 크롤링 구현해보는 것도 방법 Calendar date를 moment가 아닌 dayjs로 구현 (용량 이슈) 최적화 꼭 필요: Router - lazy loading / Code splitting 등 구현해보기 ** lighthouse로 변경 전/후 사진 찍기 (성능 최적화) 도메인 구매하여 배포 댓글, 글 작성시 ..
공통 질문 1. Virtual DOM이란 무엇이며, 실제 DOM과 어떤 차이가 있나요? DOM(Document Object Model)은 웹페이지의 구성요소들을 트리구조로 표현한 것이며 가상 돔은 실제 DOM과 구조가 완벽히 동일한 복사본 형태입니다. 가상DOM을 이용하면, 실제 DOM을 조작하는 것보다 메모리상에 올라와있는 javascript 객체를 변경하는 작업이 훨씬 더 가볍고 효율적입니다. 또한 가상DOM에서 batchupdate가 가능해졌는데, 예를 들어 인스타그램의 좋아요를 누를 때, 실제 DOM에서는 좋아요 하나를 바꾸기 위해 여러 개의 엘리먼트가 변경되어 여러 번의 갱신이 필요하지만, 가상 DOM에서는 모든 변경을 한 번에 모아서 한 번만 갱신하기 때문에 성능이 훨씬 향상될 것입니다. 2...
내 게시물의 순서가 뒤죽박죽이다 이를 해결하기 위해 정렬이 필요했다. 파이어베이스 orderBy를 사용하면 간편하다. updatedAt을 기준으로 내림차순이 정렬했다 그러나 파이어베이스 에러가 떴다 색인을 설정 안해줘서 생기는 에러였다 에러 문구 옆에 있는 링크를 클릭한다 그럼 이런 창이 바로 뜨는데 그냥 바로 저장 버튼을 누르면 된다 컬렉션을 설정하는 데에 조금 시간이 걸린다 2-3분 ?.. 바로 적용이 되는 걸 확인해볼 수 있다.
이메일과 닉네임의 중복확인 기능을 구현했다 파이어베이스에서 입력한 값이 0보다 크면 '중복' 같으면 사용가능 이메일 or 닉네임! 하지만 닉네임 쪽의 중복확인을 누르면 가입하기가 되었다 가입하기 로직을 주석 처리해놔도 가입하기가 되는 것.. 진짜 2-3시간은 해맨 것 같다. 원인은 button의 onClick이었다. 나는 react-hook-form을 썼었는데 form 태그 안에 있는 버튼의 타입은 기본적으로 onSubmit인 것을 간과했다. button의 타입을 button으로 바꾸어주었더니 해결되었다
setDoc을 통해서 Firebase에 user 정보를 저장하려고 했었다 하 근데 타입스크립트 오류가 발생하였다 타입스크립트 정의하는 건 참 어렵다.. ㅠㅠ 오류가 표시된 곳에 호버를 해봤더니 이런 메세지의 오류가 떴다 (이 호출과 일치하는 오버로드가 없습니다.) 라는 오류가 제일 싫다.. 오류가 났던 이유는 userId가 없을 수도 있어서 타입 정의가 안됐어서 그런 것이었다. undefined가 아니라는 것을 확실히 알려주어야 한다 그래서 userId를 선언해주고 if 문의 인자값으로 넣어주었더니 해결되었다
로그인을 하면 Authentication 뿐만 아니라 Firebase DB에 저장해야 했다. user의 uid를 통해 다른 페이지에서도 활용해야 했기 때문이다. 그래서 단순히 addDoc을 사용했는데 문제점이 발견되었다. 내가 원했던 것은 users 컬렉션의 문서 이름이 uid로 저장이 되어서 uid로 간편하게 정보를 불러오고 싶었던 건데 addDoc으로 여러 방법을 시도해봤지만 되지 않았다. 열심히 서칭해본 결과 setDoc을 사용하면 된다는 것을 알게 되었다. 그럼 addDoc과 setDoc의 차이점이 뭘까? 우선 공식 문서를 살펴보자. https://firebase.google.com/docs/firestore/manage-data/add-data?hl=ko Cloud Firestore에 데이터 추..
최종프로젝트에서 마이페이지 쪽을 맡게되면서 또 다시 auth 쪽을 구현하게 되었다 그 대신 이번에는 파이어베이스로! https://firebase.google.com/docs/auth/web/start?hl=ko 웹사이트에서 Firebase 인증 시작하기 | Firebase Authentication Google I/O 2023에서 Firebase의 주요 소식을 확인하세요. 자세히 알아보기 의견 보내기 웹사이트에서 Firebase 인증 시작하기 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분 firebase.google.com 파이어베이스 공식문서이다. 공식문서를 보면 쉽게 따라할 수 있다 회원가입 const signUp: SubmitHandler = async ({ email, p..
1. 상태관리를 왜 할까요? 그리고 평소 state 관리는 어떻게 하시나요? 리액트는 SPA로서, JS로 DOM을 직접 조작하는 대신 가상 DOM(Virtual DOM) 방식을 사용하여 화면 요소를 제어합니다. 이로 인해 직접 변수를 변경하는 것이 아니라 state를 통해 데이터를 관리해야만 변경 사항이 적용될 수 있습니다. 상태 관리는 주로 두 가지 방식으로 구분됩니다. 첫 번째, 지역적으로 상태 관리를 합니다. 해당 컴포넌트에서만 사용되는 state라면 컴포넌트 내에서 선언하여 관리합니다. 두 번째로는 전역적으로 상태관리를 합니다. 여러 컴포넌트에서 공유되는 상태는 전역 상태 관리 라이브러리인 redux를 사용하여 관리하고 서버로 데이터를 받았을 때는 tanstack-query의 queryKey를 통..
프로젝트에 캘린더 기능을 추가하도록 했다 우선 결과물이다 (완벽하게 완성된 것은 아님!) 환경오염을 줄이는 습관을 공유하는 글을 쓰면 캘린더에 아이콘으로 표시가 되고 그 밑 숫자는 글 쓴 횟수를 나타냈다 react-calendar를 쓰기 위해서는 설치를 해주어야 한다 npm일 경우, npm install react-calendar yarn일 경우, yarn add react-calendar 기본 코드 작성 import React, { useState } from 'react'; import Calendar from 'react-calendar'; import 'react-calendar/dist/Calendar.css'; const HabitCalendar = ({ date }: any) => { // ..
🔥 React / TypeScript 최종프로젝트🔥 개발 기간 2024.01.04 - 2024.02-07 프로젝트 명 망고(Mango) - 망해가는 지구를 고치자..! 프로젝트 소개 환경오염을 줄이는 다양한 팁과 정보를 제공하고 공유하는 '친환경 라이프' 사이트 환경보호 생활 습관 정보 제공 환경보호 제품 추천/무료나눔 나의 환경보호 습관(실천) 캘린더 관리 웹사이트를 소개하면서 환경오염에 관한 뉴스/영상 등 정보 제공 기술스택 React Firebase Typescript React-query / recoil 👤팀원 소개 및 WBS & Tasks (추후 각자 맡게될 기능을 더 추가할 예정) 리더 : 박혜민(Ashley) Write: 게시글 업로드 에디터 라이브러리를 활용하여 사람들이 게시글을 올릴 때 ..
✔️ 문제 행렬의 덧셈은 행과 열의 크기가 같은 두 행렬의 같은 행, 같은 열의 값을 서로 더한 결과가 됩니다. 2개의 행렬 arr1과 arr2를 입력받아, 행렬 덧셈의 결과를 반환하는 함수, solution을 완성해주세요. ✔️ 제한사항 행렬 arr1, arr2의 행과 열의 길이는 500을 넘지 않습니다. ✔️ 입출력 예 arr1 arr2 return [[3,4],[5,6]] [[3,4],[5,6]] [[4,6],[7,9]] [[1],[2]] [[3],[4]] [[4],[6]] 💡나의 풀이 const solution = (arr1, arr2) => { let answer = [[]]; // 큰 배열 for문 for (let i = 0; i < arr1.length; i++) { answer[i] = [..
2023.12.31 - [React/과제] - [React/TypeScript] 팀프로젝트 - 주특기 플러스 심화 / 주제는 자유 웹사이트 제작 [React/TypeScript] 팀프로젝트 - 주특기 플러스 심화 / 주제는 자유 웹사이트 제작 🔥 React / TypeScript 팀프로젝트🔥 요구 사항 : 아래 3가지 중에 한 가지를 반드시 활용해서 만들기 💡상 좋아요 또는 북마크 기능에 리액트쿼리 Optimistic Update 적용 무한스크롤 기능에 리액트쿼리 heenee.tistory.com 로그인 및 회원가입 페이지 * 토글 버튼을 통한 회원가입, 로그인 가능 메인페이지 * 읽고 있는 책의 progress bar를 통해 진행 상황을 알 수 있다 * 다 읽은 책이 완주 목록에 출력된다 도서검색 페이..
프로젝트에서 supabase를 통해 로그인과 회원가입을 구현하는 기능을 맡았다 필수로 구현해야 하는 기능 중에 react-hook-form 을 통해 유효성 검사를 하는 항목이 있어서 시도해보기로 했다! 그렇다면, 왜 react-hook-form를 쓰는 걸까? 1. TS를 기본으로 지원한다 2. 로딩 속도가 빠르다 3. 리렌더링 수가 적다 4. 코드량이 적어진다 이러한 장점들로 form을 만들 시, 사용하기에 적합하다! 우선 react-hook-form을 이용하기 위해 설치를 해야 한다. yarn add react-hook-form npm install react-hook-form 타입스크립트를 사용하기 때문에 input의 타입을 정해준다. export type Inputs = { userEmail: st..
✔️ 문제 문자열 s의 길이가 4 혹은 6이고, 숫자로만 구성돼있는지 확인해주는 함수, solution을 완성하세요. 예를 들어 s가 "a234"이면 False를 리턴하고 "1234"라면 True를 리턴하면 됩니다. ✔️ 제한사항 s는 길이 1 이상, 길이 8 이하인 문자열입니다. s는 영문 알파벳 대소문자 또는 0부터 9까지 숫자로 이루어져 있습니다. ✔️ 입출력 예 s return "a234" false "1234" true 💡나의 풀이 function solution(s) { if(s.length !== 4 && s.length !== 6) return false; for(let i=0; i