inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

묻고 답해요

173만명의 커뮤니티!! 함께 토론해봐요.

Header css justify-content 질문

해결됨

한 입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지

.Header .header_center { justify-content: center; } .Header .header_left { justify-content: flex-start; } .Header .header_right { justify-content: flex-end; } .Header { justify-content: space-between; } 이렇게 해도 같은 결과가 나오는데 두 코드 차이점이 있을까요?

  • javascript
  • react
  • node.js
현대적인유교보이 댓글 1 좋아요 0 조회수 271

인터셉팅 라우트에서 메타데이터를 적용할수 없는가요?

미해결

Next + React Query로 SNS 서비스 만들기

안녕하세요 선생님 유저정보를 모달창으로 보여주게 하기위해 아래와같이 user를 사용해서 적용했었습니다. 처음 만들었을때 메타데이터도 유저정보에 맞게 변경시켜줘야하는데 인터셉팅 라우터를 사용하면 메타데이터를 적용하지 못한다는 걸 어디서 본거같아서 테스트해보고 적용했었습니다. (user 폴더) 그리고나서 테스트를 하던중에 ux가 어색한거같아서 다시 검색해보니 인터셉팅라우트에서 메타데이터 적용하는 부분을 했다는 사람도 있는것 같더라구요 그래서 (.)tester 폴더를 만들어서 실험해봤는데 메타데이터가 적용 안되서 혹시 선생님은 인터셉트 라우트에서 메타데이터를 적용하는 방법을 아실까해서 여쭤봅니다! 📦@modal ┣ 📂(.)promise ┃ ┗ 📂form ┃ ┃ ┗ 📜page.tsx ┣ 📂(.)tester ┃ ┣ 📂[userId] ┃ ┃ ┣ 📂_component ┃ ┃ ┃ ┣ 📜UserDetailContent.tsx ┃ ┃ ┃ ┣ 📜UserDetailPromise.tsx ┃ ┃ ┃ ┣ 📜UserDetailTop.tsx ┃ ┃ ┃ ┣ 📜UserInfo.tsx ┃ ┃ ┃ ┗ 📜UsrCarousel.tsx ┃ ┃ ┣ 📂_lib ┃ ┃ ┃ ┣ 📜getSingleUser.ts ┃ ┃ ┃ ┗ 📜getUserPromise.ts ┃ ┃ ┣ 📜layout.tsx ┃ ┃ ┗ 📜page.tsx ┃ ┗ 📜default.tsx ┣ 📂user ┃ ┗ 📂[userId] ┃ ┃ ┣ 📂_component ┃ ┃ ┃ ┣ 📜UserDetailContent.tsx ┃ ┃ ┃ ┣ 📜UserDetailPromise.tsx ┃ ┃ ┃ ┣ 📜UserDetailTop.tsx ┃ ┃ ┃ ┣ 📜UserInfo.tsx ┃ ┃ ┃ ┗ 📜UsrCarousel.tsx ┃ ┃ ┣ 📂_lib ┃ ┃ ┃ ┣ 📜getSingleUser.ts ┃ ┃ ┃ ┗ 📜getUserPromise.ts ┃ ┃ ┗ 📜page.tsx ┗ 📜default.tsx 시도했던 방법은 1. page.tsx에서 직접 generateMetadata를 사용. layout.tsx를 만들고 거기에 generateMetadata를 사용후 page.tsx를 children으로 받기 여유되실때 확인해주시면 정말 감사하겠습니다!

  • react
  • next.js
  • react-query
  • next-auth
  • msw
챠챠_ 댓글 1 좋아요 0 조회수 210

getter가 정의되어 있지 않아 오류가 발생합니다.

해결됨

Vue.js 중급 강좌 - 웹앱 제작으로 배워보는 Vue.js, ES6, Vuex

안녕하세요 강사님 중급강의 스토어 모듈화까지 마치고 정상작동을 확인 한 후 터미널에서 프로젝트를 재실행 하였지만 오류로 인해 TodoList, TodoInput 등 작동 되지 않습니다. 오류는 다음과 같고 main.js와 store.js, todoApp.js 모두 import가 올바른 경로로 되어있습니다. main.js import Vue from 'vue' import App from './App.vue' import { store } from './store/store.js' new Vue({ el: '#app', store : store, render: h => h(App), }) store.js import Vue from 'vue' import Vuex from 'vuex' import todoApp from './modules/todoApp.js' Vue.use(Vuex); export const store = new Vuex.Store({ modules : { todoApp } }); todoApp.js const storage = { fetch(){ const arr = []; console.log('created') if(localStorage.length > 0 ){ for(let i = 0; i < localStorage.length; i ++){ if (localStorage.key(i) !== 'loglevel:webpack-dev-server'){ arr.push(JSON.parse(localStorage.getItem(localStorage.key(i)))); } } } return arr; } } const state= { todoItems: storage.fetch() }; const getters = { getTodoItems(state) { return state.todoItems; } }; const mutations= { addOneItem(state, todoItem) { const obj = {completed: false, item: todoItem} localStorage.setItem(todoItem, JSON.stringify(obj)); state.todoItems.push(obj); }, removeOneItem(state, payload){ localStorage.removeItem(payload.todoItem.item); state.todoItems.splice(payload.index,1); }, toggleOneItem(state, payload){ state.todoItems[payload.index].completed = !state.todoItems[payload.index].completed; localStorage.removeItem(payload.todoItem.item); localStorage.setItem(payload.todoItem.item, JSON.stringify(payload.todoItem)); }, clearAllItems(state){ localStorage.clear(); state.todoItems=[]; } }; export default{ state, getters, mutations }

  • javascript
  • vue.js
  • es6
  • vuex
brownjoon 댓글 1 좋아요 1 조회수 289

Shallow Freeze 관련 질문드립니다!

미해결

따라하며 배우는 자바스크립트 A-Z

// 얕은 동결 (shallow freeze) const obj1 = { a: 1, b: 2, c: { d: 3, e: 4 } }; Object.freeze(obj1); // 얕은 동결 obj1.a = 10; console.log(obj1); // {a: 1, b: 2, c: {d: 3, e: 4}} obj1.c.d = 30; console.log(obj1); // {a: 1, b: 2, c: {d: 30, e: 4}} 이렇게 작성했을 때 당연히 오른쪽 코멘트처럼 출력이 나올 것이라고 생각했었는데, 출력이 이렇게 나옵니다. d가 첫 콘솔 로그에도 30으로 출력되는데, 이런 현상 관련해서 구글링을 해봐도 답을 찾기가 어려워 게시판에 질문 드립니다. 혹시 왜 이런지 알 수 있을까요?

  • javascript
여노 댓글 1 좋아요 0 조회수 228

swiper-slide 적용관련 친절한 설명 감사드립니다. 근대 첫장만 되고 다음장부터

미해결

쉽고 빠르게 만드는 다양한 이미지 이펙트!

ggang_effect.js function ggangImgEffect() { var obj = $(".ggang_effect"); var makeHtml = ""; var row = 4; var columns = 8; var rowHeight = 100 / row + "%"; var columnsWidth = 100 / columns + "%"; var imgWidth = 100 * columns + "%"; var imgHeight = 100 * row + "%"; for (var i = 0; i < row; i++) { // console.log('-행-:'+i); for (var j = 0; j < columns; j++) { var delaySpeed = (columns - j - i * 0.5) * 0.25; var left = -j * 100 + "%"; var top = -i * 100 + "%"; makeHtml += '<div class="img_box" style="width:' + columnsWidth + "; height:" + rowHeight + "; transition-delay:" + delaySpeed + 's; ">'; makeHtml += '<div class="img_position" style="width:' + imgWidth + "; height:" + imgHeight + "; left:" + left + "; top:" + top + ';"></div>'; makeHtml += "</div>"; // console.log('열:'+j); } } $(obj).append(makeHtml); setTimeout(function () { $(obj).find(".img_box").addClass("active"); }, 200); } $(function () { ggangImgEffect(); }); const mySwiper = new Swiper(".swiper-container", { effect: "fade", loop: true, speed: 1500, autoplay: { delay: 5000, disableOnInteraction: false, }, navigation: { nextEl: ".swiper-button-next", prevEl: ".swiper-button-prev", }, on: { slideChange: function () { var thisSlide = $(".swiper-container").find(".swiper-slide").eq(this.activeIndex); ggangImgEffect(thisSlide, this.activeIndex); }, }, });

  • HTML/CSS
  • javascript
  • jquery
  • 인터랙티브-웹
foxball 댓글 2 좋아요 0 조회수 302

bun, biome 사용 질문

해결됨

Next.js 시작하기

안녕하세요, 강의 잘 보고 있습니다. React Native 프로젝트를 진행할 때 Bun을 사용하여 패키지 매니징을 했을 때 굉장히 개발 경험이 쾌적했던 기억이 있습니다. 그리고 비교적 최근 ESLint와 Prettier의 단점을 상쇄해줄 Biome라는 솔루션이 나와서 도입해보려고 하던 상태였습니다. 선생님은 Bun, Biome에 대해 어떻게 생각하시는지 궁금합니다!

  • javascript
  • react
  • next.js
popo 댓글 2 좋아요 0 조회수 371

트랜잭션 queryRunner 더러운 읽기 , 반복 못하는 읽기 기타 등등 질문있습니다.

해결됨

[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스

예시 코드를 보면 트랜잭션 이용해서 조회하고, 작성하고 하시는데 이거는 예시를 위해서 그렇게 하신걸까요? 실무에서는 한가지 작업할 때는 트랜잭션 사용안하고 바로 디비에 저장하고, 조회하고 하는걸까요?

  • javascript
  • node.js
  • docker
  • rest-api
  • nestjs
반가우면반갑다고해 댓글 2 좋아요 0 조회수 182

[숙제] minHeap 구현, maxHeap -> minHeap , minHeap -> maxHeap

해결됨

비전공자의 전공자 따라잡기 - 자료구조(with JavaScript)

minHeap 구현 class MinHeap { // 최소힙 arr = []; #reheapUp(index) { if (index > 0) { const parentIndex = Math.floor((index - 1) / 2); if (this.arr[index] < this.arr[parentIndex]) { const tmp = this.arr[index]; this.arr[index] = this.arr[parentIndex]; this.arr[parentIndex] = tmp; this.#reheapUp(parentIndex); } } } insert(value) { const index = this.arr.length; this.arr[index] = value; // 마지막에 값을 넣어준다. this.#reheapUp(index); } #reHeapDown(index) { const leftIndex = index * 2 + 1; // 왼쪽 Index if (leftIndex < this.arr.length) { const rightIndex = index * 2 + 2; const smaller = this.arr[leftIndex] < this.arr[rightIndex] ? leftIndex : rightIndex; if (this.arr[index] > this.arr[smaller]) { const temp = this.arr[index]; this.arr[index] = this.arr[smaller]; this.arr[smaller] = temp; this.#reHeapDown(smaller); } } } remove() { // root만 remove if (this.arr.length === 0) { return false; } if (this.arr.length === 1) { // 마지막 하나 남으면 pop해서 리턴해주기 return this.arr.pop(); } const root = this.arr[0]; this.arr[0] = this.arr.pop(); this.#reHeapDown(0); return root; } sort() { // 힙 정렬 const sortedArray = []; while (this.arr.length > 0) { sortedArray.push(this.remove()); } return sortedArray; } search(value) { for (let i = 0; i < this.arr.length; i++) { if (this.arr[i] === value) { return i; } } return null; } // 특정값 수정 update(value, newValue) { const index = this.search(value); if (index === null) { return false; } this.arr[index] = newValue; for (let i = Math.floor(this.arr.length / 2 - 1); i >= 0; i--) { this.#heapify(i); } } // 특정값 삭제 removeValue(value) { const index = this.search(value); if (index === null) { return false; } // 특정값의 index를 splice를 이용하여 없애버린다. this.arr.splice(index, 1); for (let i = Math.floor(this.arr.length / 2 - 1); i >= 0; i--) { // 이렇게 했을때 힙이 깨질 수 있기 떄문에 heapify 해준다 this.#heapify(i); } } transFormMaxHeap() { for (let i = Math.floor(this.arr.length / 2 - 1); i >= 0; i--) { // i가 2부터 시작 // 이렇게 했을때 힙이 깨질 수 있기 떄문에 heapify 해준다 this.#maxHeapify(i); } return this.arr; } // 특정값을 수정하거나 특정값을 삭제하거나 #heapify(index) { const leftIndex = index * 2 + 1; // 왼쪽 Index 78의 왼쪽 5: 23 const rightIndex = index * 2 + 2; // 오른쪽 6: undefined const smaller = (this.arr[leftIndex] || Number.MAX_SAFE_INTEGER) < (this.arr[rightIndex] || Number.MAX_SAFE_INTEGER) ? leftIndex : rightIndex; if (this.arr[index] > this.arr[smaller]) { const temp = this.arr[index]; this.arr[index] = this.arr[smaller]; this.arr[smaller] = temp; this.#heapify(smaller); } } #maxHeapify(index) { const leftIndex = index * 2 + 1; // 왼쪽 Index const rightIndex = index * 2 + 2; const bigger = (this.arr[leftIndex] || 0) > (this.arr[rightIndex] || 0) ? leftIndex : rightIndex; if (this.arr[index] < this.arr[bigger]) { const temp = this.arr[index]; this.arr[index] = this.arr[bigger]; this.arr[bigger] = temp; // 재귀 호출 해주어야 된다! this.#maxHeapify(bigger); } } } 최소 힙 insert const minheap = new MinHeap(); minheap.insert(78); minheap.insert(56); minheap.insert(45); minheap.insert(32); minheap.insert(23); minheap.insert(19); minheap.insert(8); // 결과 [8, 32, 19, 78, 45, 56, 23] 결과 그림 최소힙 remove const minheap = new MinHeap(); minheap.insert(78); minheap.insert(56); minheap.insert(45); minheap.insert(32); minheap.insert(23); minheap.insert(19); minheap.insert(8); minheap.remove(); minheap.remove(); minheap.remove(); minheap.remove(); minheap.remove(); minheap.remove(); // 8 , 32, 19, 78, 45 ,56, 23 // 19, 32, 23, 78, 45, 56 // 23, 32, 56, 78, 45 // 32, 45, 56, 78 // 45, 78, 56 // 56, 78 // 78 최소힙 update const minheap = new MinHeap(); minheap.insert(78); minheap.insert(56); minheap.insert(45); minheap.insert(32); minheap.insert(23); minheap.insert(19); minheap.insert(8); minheap.update(32, 90); // [8, 32, 19, 78, 45, 56, 23] // 결과 -> [8, 45, 19, 78, 90, 56, 23] 최소힙 removeValue const minheap = new MinHeap(); minheap.insert(78); minheap.insert(56); minheap.insert(45); minheap.insert(32); minheap.insert(23); minheap.insert(19); minheap.insert(8); minheap.removeValue(19); // [8, 45, 19, 78, 90, 56, 23] // 결과 -> [8, 45, 23, 90, 56, 78] 최소힙 -> 최대힙 const minheap = new MinHeap(); minheap.insert(78); minheap.insert(56); minheap.insert(45); minheap.insert(32); minheap.insert(23); minheap.insert(19); minheap.insert(8); console.log(minheap.transFormMaxHeap()); // [ 8, 32, 19, 78, 45, 56, 23 ] // 결과 -> [78, 45, 56, 32, 8, 19, 23] 최대힙 -> 최소힙 class MaxHeap { arr = []; #reheapUp(index) { if (index > 0) { const parentIndex = Math.floor((index - 1) / 2); if (this.arr[index] > this.arr[parentIndex]) { // 값 바꾸기 const tmp = this.arr[index]; this.arr[index] = this.arr[parentIndex]; this.arr[parentIndex] = tmp; this.#reheapUp(parentIndex); } } } insert(value) { const index = this.arr.length; this.arr[index] = value; // 마지막에 값을 넣어준다. this.#reheapUp(index); } #reHeapDown(index) { const leftIndex = index * 2 + 1; // 왼쪽 Index if (leftIndex < this.arr.length) { // 만약에 왼쪽 인덱스가 총 배열의 길이보다 작은경우 const rightIndex = index * 2 + 2; const bigger = this.arr[leftIndex] > this.arr[rightIndex] ? leftIndex : rightIndex; if (this.arr[index] < this.arr[bigger]) { const temp = this.arr[index]; this.arr[index] = this.arr[bigger]; this.arr[bigger] = temp; this.#reHeapDown(bigger); } } } remove() { // root만 remove if (this.arr.length === 0) { return false; } if (this.arr.length === 1) { // 마지막 하나 남으면 pop해서 리턴해주기 return this.arr.pop(); } const root = this.arr[0]; this.arr[0] = this.arr.pop(); this.#reHeapDown(0); return root; } sort() { // 힙 정렬 const sortedArray = []; while (this.arr.length > 0) { sortedArray.push(this.remove()); } return sortedArray; } search(value) { for (let i = 0; i < this.arr.length; i++) { if (this.arr[i] === value) { return i; } } return null; } // 특정값 수정 update(value, newValue) { const index = this.search(value); if (index === null) { return false; } this.arr[index] = newValue; for (let i = Math.floor(this.arr.length / 2 - 1); i >= 0; i--) { this.#heapify(i); } } // 특정값 삭제 removeValue(value) { const index = this.search(value); if (index === null) { return false; } // 특정값의 index를 splice를 이용하여 없애버린다. this.arr.splice(index, 1); for (let i = Math.floor(this.arr.length / 2 - 1); i >= 0; i--) { // 이렇게 했을때 힙이 깨질 수 있기 떄문에 heapify 해준다 this.#heapify(i); } } transFromMinHeap() { for (let i = Math.floor(this.arr.length / 2 - 1); i >= 0; i--) { // i가 2부터 시작 // 이렇게 했을때 힙이 깨질 수 있기 떄문에 heapify 해준다 this.#minHeapify(i); } return this.arr; } // 특정값을 수정하거나 특정값을 삭제하거나 #heapify(index) { const leftIndex = index * 2 + 1; // 왼쪽 Index const rightIndex = index * 2 + 2; const bigger = (this.arr[leftIndex] || 0) > (this.arr[rightIndex] || 0) ? leftIndex : rightIndex; if (this.arr[index] < this.arr[bigger]) { const temp = this.arr[index]; this.arr[index] = this.arr[bigger]; this.arr[bigger] = temp; this.#heapify(bigger); } } // 특정값을 수정하거나 특정값을 삭제하거나 #minHeapify(index) { const leftIndex = index * 2 + 1; // 왼쪽 Index 78의 왼쪽 5: 23 const rightIndex = index * 2 + 2; // 오른쪽 6: undefined const smaller = (this.arr[leftIndex] || Number.MAX_SAFE_INTEGER) < (this.arr[rightIndex] || Number.MAX_SAFE_INTEGER) ? leftIndex : rightIndex; if (this.arr[index] > this.arr[smaller]) { const temp = this.arr[index]; this.arr[index] = this.arr[smaller]; this.arr[smaller] = temp; this.#minHeapify(smaller); } } } const heap = new MaxHeap(); heap.insert(8); heap.insert(19); heap.insert(23); heap.insert(32); heap.insert(45); heap.insert(56); heap.insert(78); console.log(heap.transFormMinHeap()); // [78, 32, 56, 8, 23, 19, 45] // -> 결과 [8, 23, 19, 32, 78, 56, 45] 질문1) maxheap(minheap) 코드 구현시 heapify 메서드에서 재귀호출 되어야 되지 않는가요? 강의에서는 heapify 메서드 구현시 재귀 호출 부분이 빠져있는것 같아서 질문 드립니다. 아니라면 죄송합니다. #heapify(index) { const leftIndex = index * 2 + 1; // 왼쪽 Index const rightIndex = index * 2 + 2; const bigger = (this.arr[leftIndex] || 0) > (this.arr[rightIndex] || 0) ? leftIndex : rightIndex; if (this.arr[index] < this.arr[bigger]) { const temp = this.arr[index]; this.arr[index] = this.arr[bigger]; this.arr[bigger] = temp; // 여기 빠진것 같습니다! this.#heapify(bigger); } }

  • javascript
  • 코딩-테스트
  • 알고리즘
rhkdtjd_12 댓글 1 좋아요 1 조회수 264

기능

미해결

따라하며 배우는 리액트 A-Z[19버전 반영]

taliWindcss를 사용해서 클래스네임에 작성을하고 마우스를 가져다 대면 75% 이런식으로 나온다고 하셨는데 아무것도 안나오는데 어떻게 하나요? 이 부분 강사님처럼 모양 바꾸고 싶은데 어떻게 하나요?

  • react
  • redux
  • tdd
  • typescript
  • next.js
  • 소프트웨어-테스트
Full Stack 개발자 댓글 1 좋아요 0 조회수 222

오류가 안보여요

미해결

따라하며 배우는 리액트 A-Z[19버전 반영]

Form 컴포넌트를 신규로 만들어서 기존 컴포넌트에서 가져왔는데 강의에서는 오류가 표시가 되지만 저는 오류가 나타나지 않아서 현재, Form.js 파일에는 오류가 없는걸로 나오는데 어떻게 해야 하나요?

  • react
  • redux
  • tdd
  • typescript
  • next.js
  • 소프트웨어-테스트
Full Stack 개발자 댓글 1 좋아요 0 조회수 224

Infinite Scroll: pageParam 질문

해결됨

Next + React Query로 SNS 서비스 만들기

제로초님 안녕하세요! 제가 개발중인 프로젝트에서 최신순, 조회순 정렬과 키워드 검색을 통해 도서 목록을 출력하고 있는데요. Infinite scroll을 적용하려다 보니 강의에서 처럼 cursor로 전달할 postId 같은 값이 없고, 도서 데이터의 키 값은 uuid로 되어있습니다. 커서 기반으로 개발하려면 백엔드에서 별도 값을 내려준다거나, 조회 SQL을 변경 해야 할까요? 어떤 적절한 방법이 있을지 궁금합니다. 감사합니다!

  • react
  • next.js
  • react-query
  • next-auth
  • msw
도전적인 제비 댓글 1 좋아요 0 조회수 194

JS 변수 선언 3단계 관련 문의드립니다

해결됨

let x = x; 를 선언했을 때 호이스팅으로 let x; //선언 x = x; //초기화&할당 //reference error 발생 으로 알고 있습니다. TDZ에 들어간 x를 참조하지 못하기 때문인데요 x = x; 가 undefined으로 초기화된 후 x가 할당된 것인지 아니면 바로 x로 값 x가 할당되는 것인지가 궁금합니다. 전자라면 x=undefined;로 초기화되어 TDZ을 벗어나게 되는데 REFERENCE ERROR가 발생하지 않을 것 같긴 한데요... 순서는 선언, 초기화, 할당이라서 헷갈립니다.

  • js
  • javascript
hiramap 댓글 1 좋아요 0 조회수 267

자료 없음

미해결

따라하며 배우는 노드, 리액트 시리즈 - 유튜브 사이트 만들기

https://github.com/jaewonhimnae/%20boilerplate-mern-stack this is not the ~~~~~ 없네요 자료를 다운받을 수 없는 것인가요?

  • react
  • redux
  • node.js
  • mongodb
김동호 댓글 1 좋아요 0 조회수 362

nextjs 배포 방식

미해결

Next + React Query로 SNS 서비스 만들기

next14에서 배포 시 페이지는 클라이언트 컴포넌트를 명시한 상태에서 next build를 실행시에 fetch 에러가 나오는데 next를 배포시에는 백엔드서버가 항상 켜져있어야되나요?

  • react
  • next.js
  • react-query
  • next-auth
  • msw
김연호 댓글 2 좋아요 0 조회수 376

footer

미해결

포트폴리오 사이트 만들고 배포까지! : 웹 개발 입문 활용편

수업을 따라하다 보니 footer 부분에서 footer 윗 부분에 살짝 파랑색 라인이 보입니다. 이걸 없애고 싶으면 어떻게 해야하는 건가요 ?

  • HTML/CSS
  • javascript
  • 포트폴리오
  • github-pages
디디 댓글 1 좋아요 0 조회수 256

[아코디언 1/6 챕터] 클로저 활용 질문 있습니다.

해결됨

코어 프런트엔드 UI - Part 1

안녕하세요! 이제 막 강의를 듣고 있는 배정규라고 합니다. 아코디언 강의를 듣고나니 UI 컴포넌트 개발뿐만 아니라 자바스크립트와 프론트엔드 개발의 실무 팁까지 배울 수 있겠다라는 기대감이 생기네요 🙂 질문은 toggleItem 함수를 클로저를 활용해서 개선을 해주셨는데요, 왜 클로저로 개선을 해주셨는지가 궁금합니다. 클로저를 활용했을 때와 이전 함수와 비교했을 때 어떤 이점이 생기는지 크게 와닿지가 않아서요. 왜 toggleItem 함수를 클로저를 활용해서 개선해주셨는지 궁금합니다 😃

  • react
  • typescript
  • dom
  • ui
  • vanilla-js
배정규 댓글 2 좋아요 2 조회수 471

테스트 오류

미해결

실무에 바로 적용하는 프런트엔드 테스트 - 1부. 테스트 기초: 단위・통합 테스트

수업에서 처럼 이렇게 코드를 작성했을 때는 오류가 발생하는데 placeholder를 넣으면 에러가 나지않습니다. 왜그런지 알 수 있을까요?!

  • javascript
  • react
  • 소프트웨어-테스트
  • vitest
고운 고양이 댓글 2 좋아요 0 조회수 276

배포테스트할때 클라이언트에서 api호출하면 쿠키가 전달되지 않고있습니다.

해결됨

Next + React Query로 SNS 서비스 만들기

안녕하세요 선생님 배포테스트할때 클라이언트에서 api호출하면 쿠키가 전달되지 않고있습니다. 클라이언트에서는 credentials: 'include'를 적용했고 const response = await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/user/setting`, { method: 'PATCH', credentials: 'include', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(userSettingObj), }); if (response.ok) { const sessionUpdateInfo = await response.json(); await updateSession(sessionUpdateInfo); router.push('/'); } 서버에서는 const express = require('express'); const cors = require('cors'); const passport = require('passport'); const session = require('express-session'); const cookieParser = require('cookie-parser'); const dotenv = require('dotenv'); const morgan = require('morgan'); const path = require('path'); const hpp = require('hpp'); const helmet = require('helmet'); const postRouter = require('./routes/post'); const postsRouter = require('./routes/posts'); const userRouter = require('./routes/user'); const usersRouter = require('./routes/users'); const db = require('./models'); const passportConfig = require('./passport'); dotenv.config(); const app = express(); db.sequelize.sync() .then(() => { console.log('db 연결 성공') }) .catch(console.error); passportConfig(); if (process.env.NODE_ENV === 'production') { app.use(morgan('combined')); app.use(hpp()); app.use(helmet()); } else { app.use(morgan('dev')); } app.use( cors({ origin: ['http://localhost:3000', 'whatisyourmbti.com', 'http://43.201.56.221'], // true or * // access-control-allow-origin가 true된다. --> 다른 도메인끼리 api 요청 credentials: true, // access-control-allow-credential가 true된다. --> 다른 도메인끼리 쿠키 전달 method: '*', }) ); // 프론트에서 보낸 정보를 req.body에 넣어준다. 순서 중요! app.use(express.json()); // json 형식으로 보냈을때 데이터 처리해줌 app.use(express.urlencoded({ extended: true })); // form submit으로 보냈을 때 데이터 처리해줌 app.use(cookieParser(process.env.COOKIE_SECRET)); app.use(session({ saveUninitialized: false, resave: false, secret: process.env.COOKIE_SECRET, cookie: { httpOnly: true, secure: false, } })); app.use(passport.initialize()); app.use(passport.session()); app.use((req, res, next) => { console.log('Session ID:', req.sessionID); console.log('Cookies:', req.cookies); console.log('Signed Cookies:', req.signedCookies); next(); }); app.get('/', (req, res) => { res.send('hello express'); }); app.get('/api', (req, res) => { res.send('hello api'); }); app.use('/post', postRouter); app.use('/posts', postsRouter); app.use('/user', userRouter); app.use('/users', usersRouter); app.listen(80, () => { console.log('서버 실행 중!'); }); credentials: true, 쿠키옵션을 설정해주었는데 0|app | Session ID:---------------------------- U8DRuillNv2DBRmexmO1mZZ7fGJeWXCw 0|app | Cookies:------------------------------- [Object: null prototype] {} 0|app | Signed Cookies:------------------------ [Object: null prototype] {} 이런식으로 쿠키값이 전달되고 있지 않아서 유저 정보가 필요한(로그인 확인)로직에서 401에러가 떨어지게 됩니다. app.use(session({ saveUninitialized: false, resave: false, secret: process.env.COOKIE_SECRET, cookie: { httpOnly: true, secure: false, } })); 위부분들을 검색해보고 바꿔보기도 했는데, 잘안되더라구요. 클라이언트의 ip는 http://43.201.56.221입니다. 쿠키는 로그인 후 프론트서버에서 브라우저에 삽입해주고 있습니다. console.log(`${process.env.NEXT_PUBLIC_BASE_URL}/user/login ---------------------login api`); const authResponse = await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/user/login`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ ...credentials }), } ); // 프론트서버에서 백엔드서버의 로그인 토큰을 받아온것. 토큰은 문자열이라서 // cookie라이브러리로 객체로 만들어준다. let setCookie = authResponse.headers.get('Set-Cookie'); console.log('set-cookie', setCookie); if (setCookie) { const parsed = cookie.parse(setCookie); console.log(parsed, '---------------parsed cookie'); // 브론트서버에서 브라우저에 쿠키를 심어준다. // 프론트서버에 쿠키를 심으면 안된다! 왜냐하면 프론트서버는 서버라서 공용이다. // 여러 브라우저가 전부 프론트서버르 바라본다. 개인정보 유출 문제 발생할 수 있다. cookies().set('connect.sid', parsed['connect.sid'], parsed); // parsed = 나머지 옵션들 } console.log(authResponse, '--------------------------------authResponse'); let user = await authResponse.json(); console.log(user, '--------------------------------user'); // console.lo(authResponse); if (!authResponse.ok) { return null; } // return user object with the their profile data return { ...user, email: user.email, name: user.nickname, image: user.image, id: user.id, } } catch (err) { console.error('로그인 에러', err); } 그리고 cors에러는 발생하지 않고있습니다. 혹시 수정해야할 코드나, 참고해야할 부분이 있다면 알려주시면 감사하겠습니다.

  • react
  • next.js
  • react-query
  • next-auth
  • msw
챠챠_ 댓글 2 좋아요 0 조회수 939

next server action, client fetch 관련 질문입니다.

해결됨

Next + React Query로 SNS 서비스 만들기

안녕하세요 제로초님 저는 react app 개발만 조금 해봤는데, next 강의에서 server action을 처음 접하면서 헷갈려서 질문 드립니다. 예를 들어서 게시판 목록을 불러올 때 server fetch를 통해 화면에 출력하고 있고, 무한스크롤이나 add, edit, delete 동작 등을 server action으로 할 수 있다는 것을 알았는데요. 그렇다면 next app을 개발할 때는 client fetch는 전혀 필요가 없는 건가요? 아니면 어떤 필요에 따라 client fetch와 server fetch를 혼용해서 사용해야 하는 건지.. 궁금합니다. 감사합니다!

  • react
  • next.js
  • react-query
  • next-auth
  • msw
도전적인 제비 댓글 1 좋아요 0 조회수 201

파일 저장시 prettier가 의도적으로 줄 바꿈한 문장을 한 줄로 합쳐버립니다.

해결됨

한 입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지

<저장 전> <저장 후> <저장 전> <저장 후> <저장 전> <저장 후> 파일 저장을 하면 prettier가 실행되면서 의도적으로 줄 바꿈 했던 것을 한 줄로 합쳐버립니다. 그렇다고 format on save를 끄거나 prettier를 끄고 싶지는 않습니다. 한 줄로 합쳐지지만 않게 하고 싶은데 어떻게 해야 할까요?

  • javascript
  • react
  • node.js
무빙락 댓글 1 좋아요 0 조회수 434

인기 태그

인프런 TOP Writers

주간 인기글