묻고 답해요
156만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결React 완벽 마스터: 기초 개념부터 린캔버스 프로젝트까지
빨간 밑줄 질문이요..
위와 같이 해당 변수나 값을 선언한거를 사용하지 않으면 이렇게 빨간 밑줄이 생기는데요. 이거 없앨수 없나요? 거슬리네요..ㅠ
-
해결됨[React 2부] 고급 주제와 훅
ProductItem에서 onClick = {onClick}을 달지 않아도 되는 이유
안녕하세요 강사님 수업 잘 듣고 있습니다. OrderableProductItem.jsx에서 컨텍스트의 컨슈머 안에 렌더 프롭을 children으로 만들고changePath를 이용해서 주문하기 버튼을 누르면 cart로 이동하지 않습니까?그런데productItem.jsx에서는 {onClick && ( <Button styleType={"brand"} >주문하기</Button> )}1. 이렇게 정의되어서 onClick 메서드를 받기만 하고 직접 활용하지 않습니다. 그럼에도 불구하고 Context를 통해 changePath가 작동할 수 있는 이유가 무엇인가요?코드의 가독성을 위해서는 productItem.jsx에서onClick ={onClick}을 달아주어야 하지 않나요?
-
해결됨[React 2부] 고급 주제와 훅
replaceState를 쓰지 않는 대안
안녕하세요 강사님 pushState를 작성하고 popState를 쓰는 부분에 있어서 에러가 발생했는데 이는 replaceState를 안써서 초기 상태에 대한 정보가 없어서 그렇다고 이해했습니다. 그런데, replaceState를 안쓰고 event.currentTarget.document.location.pathname 속성을 써도 정상적으로 작동하는듯한데 이 방식은 적절하지 않다고 보시나요? handleChangePath(path){ this.setState({path}) window.history.pushState({}, "", path) onpopstate = (event) => { console.log(this.state.path) this.setState({path : event.currentTarget.document.location.pathname}) }; }
-
미해결React 완벽 마스터: 기초 개념부터 린캔버스 프로젝트까지
조건부 렌더링에서 로직 처리 차이
export default function CourseItem({title, description, thumbnail, isFavorite}) { let defaultIconTag = "/img/heart/heart-icon.svg" if (isFavorite) { defaultIconTag = "/img/heart/heart-fill-icon.svg" } return ( <article className="course"> <img className="course__img" src={thumbnail} alt="강의 이미지"/> <div className="course__body"> <div className="course__title">{title}</div> <div className="course__description">{description}</div> </div> <div className="course__icons"> <button className="btn"> <img className="icon-heart" src={defaultIconTag} /> </button> </div> </article> ); }저는 기존 CourseItem메서드 내에서 변수를 생성해서 만들었는데 강의에서는 새로운 메서드를 생성해서 진행하더라고요.메서드를 따로 생성해서 버튼 태그랑 묶어서 같이 넘기신 이유가 있나요? 현업에서 어떤 방식을 더 선호할까요?
-
미해결React 완벽 마스터: 기초 개념부터 린캔버스 프로젝트까지
axios post 사용할때 페이지 새로고침 문제
Home.jsx이렇게 하고 import { useEffect, useState } from 'react'; import HomeDataLength from '../components/HomeDataLength.jsx'; import HomeSearch from '../components/HomeSearch.jsx'; import CanvasItemList from '../components/CanvasItemList.jsx'; import SearchBar from '../components/SearchBar.jsx'; import GridFlexBTN from '../components/GridFlexBTN.jsx'; import { deleteHome, createHome, getHome } from '../api/home.js'; import { v4 as uuid } from 'uuid'; import dayjs from 'dayjs'; export default function Home() { const [isGrid, setIsGrid] = useState(true); const [search, setSearch] = useState(''); const [data, setData] = useState([]); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(false); useEffect(() => { const api = async () => { setIsLoading(true); setError(false); try { const response = await getHome(''); setData(response.data); } catch (err) { setError(err); } finally { setIsLoading(false); } }; api(); }, []); const [isLoadingCreate, setIsLoadingCreate] = useState(false); const [createError, setCreateError] = useState(false); // 등록버튼 누르면 새로운 데이터 저장 const handleNewCreate = async () => { // setIsLoadingCreate(true); // setCreateError(false); // try { const id = uuid(); const newCreate = { id, date: dayjs().format('YYYY-MM-DD HH:mm:ss'), text: `${id.substring(0, 4)}-테스트`, category: '테스트', }; await createHome(newCreate); console.log(123); // const res = await getHome(); // setData(res.data); // } catch (err) { // setCreateError(err); // console.log(createError, 'createError'); // } finally { // setIsLoadingCreate(false); // } }; const handleText = text => { const searchData = data.filter(d => d.text.toLowerCase().includes(text.toLowerCase()), ); if (searchData.length === 0) { setSearch(null); } else { setSearch(searchData); } }; const handleDelete = async id => { // const newData = data.filter(d => d.id !== id); // setData(newData); await deleteHome(id); }; return ( <> <> <div className="flex flex-col md:flex-row justify-between items-center"> <button className="hover:bg-blue-400 bg-blue-500 text-white rounded-md text-bold p-3" onClick={handleNewCreate} > 등록하기 </button> {isLoadingCreate && <p>등록중</p>} {createError && <p>{createError}</p>} <SearchBar handleText={handleText} /> <GridFlexBTN setIsGrid={setIsGrid} isGrid={isGrid} /> </div> <HomeDataLength data={data} error={error} isLoading={isLoading} /> <HomeSearch search={search} /> {!isLoading && !error && ( <CanvasItemList data={data || []} search={search} isGrid={isGrid} handleDelete={handleDelete} /> )} </> </> ); } home.js 파일은 아래와 같은 상태이면 import { home } from './http'; // 목록 조회 export const getHome = () => { return home.get('/'); }; // 등록 export const createHome = newCreate => { try { console.log('ㅅㅣ작'); } catch (error) { console.log('에러'); } finally { console.log('종료'); } // debugger; return home.post('/', newCreate); }; // 수정 // 삭제 export const deleteHome = id => { return home.post('/', id); }; db는 server-json을 사용하고 있습니다.그런데 get 요청을 할때는 잘 작동하는데post로 등록하거나 삭제할때는 db에 정상 등록, 삭제되는데 화면이 새로고침이 되버리는 상태입니다. Home.jsx 화면이 리렌더링이 되도록 하고싶은데 새로고침은 왜 그런지 모르겠습니다. postman으로도 post로 db에 저장했는데 리액트 화면이 자동으로 새로고침 되버립니다. 구글링도 해봤는데 해결이 안되서 문의드립니다.혹시나 해서 db.json이 변경되면 화면도 변경될까 싶어서 을 db.json --watch로만 해보고 --watch도 없애봤는데 안됩니다. const handleNewCreate = async () => { console.log('시작1'); const id = uuid(); const newCreate = { id, date: dayjs().format('YYYY-MM-DD HH:mm:ss'), text: `${id.substring(0, 4)}-테스트`, category: '테스트', }; const data = await createHome(newCreate); console.log(data, 'data'); console.log('시작2'); debugger; };debugger를 사용했을때이렇게 데이터 나오는데 디버거 끄는 순간 바로 화면이 새로고침 되고 있습니다. 그리고 콘솔창도 새창으로 이전 내역이 다 사라지는 상태입니다.
-
해결됨[React 2부] 고급 주제와 훅
setValue 메서드를 바인딩 해야 하는 이유
안녕하세요:) 수업 잘 듣고 있습니다.2.1.4 공급자와 소비자 강의 中 7:04에서 this.setValue = this.setValue.bind(this)를 작성하셨는데 리액트에서의 바인딩이란 자식 컴포넌트에 프로퍼티로 이벤트 핸들러와 다른 함수들을 전달할 때,구체적으로 핸들러 안에서 부모 컴포넌트에 접근할 필요가 있을 때 해야 하는 것으로 알고 있습니다. 그런데, setValue는 자식 컴포넌트로 이벤트 핸들러를 넘겨주는 상황이 아닌데 이벤트 바인딩을 해야 하는 이유가 무엇인지 궁금합니다.화살표 함수를 활용하면 자연스럽게 바인딩이 되는데 왜 화살표함수를 안쓰신 건지 궁금합니다.
-
미해결React 완벽 마스터: 기초 개념부터 린캔버스 프로젝트까지
iTerm으로 폴더 만드는 부분에 대해 질문이 있습니다.
안녕하세요 현재 맥북을 사용중이고 강의영상처럼 iTerm으로 명령어를 작성해서 폴더를 만들고 비주얼스튜디오까지 열기부분에서 저는 외장하드를 연결해서 배경화면에 있는 외장하드폴더 안에 짐코딩강의라는 폴더 안에 react-test 라는 폴더를 만들어 사용할려고 하는데 이렇게 되면 명령어를 어떻게 작성하면 되는지 궁금합니다.
-
미해결React 완벽 마스터: 기초 개념부터 린캔버스 프로젝트까지
Link 태그가 동작하지 않습니다.
검사를 해보면 a 태그로는 바뀌어 있는데 커서가 pointer가 되지 않고 클릭이 되지 않습니다.그런데 Link 태그를 NavLink로 바꾸면 router 이동이 정상적으로 잘 됩니다.node - v22.12.0react-router-dom - ^7.1.1strick 모드가 문제 일 수 있어 main.tsx에 strick 모드도 제거해보았지만 LInk 태그로는 router 이동이 되지 않았습니다.혹시 그 이유를 알 수 있을까요?형태는 이렇습니다.
-
미해결React 완벽 마스터: 기초 개념부터 린캔버스 프로젝트까지
추가 기능 문의
안녕하세요!강의 잘 듣고 있습니다!!! 🙂React Query 공식 문서에 나오는 페이지네이션 기능에 대해 궁금한 점이 있습니다. 제가 직접 시도해봤는데 어려워서 그런데, 혹시 이 기능을 강의에서 다룰 계획이 있으실까요? 선생님께서 설명을 잘해주셔서 강의가 있다면 정말 좋을 것 같습니다. 감사합니다.
-
미해결React 완벽 마스터: 기초 개념부터 린캔버스 프로젝트까지
map 사용이후 렌더링이 안됩니다
import Card from "../Card.jsx"; import Courseitem from "./Courseitem.jsx"; function CourseListCard({ items }) { return ( <Card title={"강의 목록"}> <div className="courses"> {items.map((item) => { return <Courseitem {...item} />; })} </div> </Card> ); } export default CourseListCard;강사님과 동일한 코드를 작성했는데도 저는 렌더링이 되지 않습니다 ㅠㅠ
-
미해결React 완벽 마스터: 기초 개념부터 린캔버스 프로젝트까지
input value props 를 설정하면 입력이 안되는 이유
export default function FormComponent() { return ( <form onSubmit={handleSubmit}> <input name="first" type="text" value="첫번째" /> <input name="second" type="text" value="두번째" /> <button type="submit">Submit 버튼</button> </form> ); }위와 같이 input 에 value props 를 설정하면 왜 타이핑이 안되는지 이해가 잘 안됩니다. 순수 HTML 에서는 input 요소의 value 속성은 초기값이고 변화된 현재값은 DOM 의 value 프로퍼티를 통해 가져올 수 있다고 알고있는데 React 에서는 뭐가 달라지길래 value props 를 설정만 하더라도 input 에 입력값이 변화되지 않는 것인지 알고 싶어요!
-
미해결React 완벽 마스터: 기초 개념부터 린캔버스 프로젝트까지
혹시 깃 주소를 좀 알수 있을까요???
수업내용이 있는 깃주소를 알 수 있을까요?노션에 찾아봤는데 없는것 같아서요.
-
미해결React 완벽 마스터: 기초 개념부터 린캔버스 프로젝트까지
컴포넌트에서 삼항 연산자를 이용하여 JSX 를 반환할 때 궁금한 점
function HeartIconBtn({ isFavorite = false }) { return ( <button style={{ backgroundColor: 'white', border: 'none', }} > {isFavorite ? ( <img style={{ width: '32px', color: 'red' }} src="/images/heart-fill-icon.svg" alt="" /> ) : ( <img style={{ width: '32px', color: 'red' }} src="/images/heart-icon.svg" alt="" /> )} </button> ); } function LinkIconBtn({ link }) { return ( <> {link ? ( <a href={link} target="_blank"> <img style={{ width: '36px' }} src="/images/link-icon.svg" alt="lecture link" /> </a> ) : null} </> ); } export default function CourseItem({ image, title, description, isFavorite, link, }) { return ( <> <div style={{ display: 'flex', gap: '30px', justifyContent: 'center', alignItems: 'center', }} > <img style={{ width: '20%', borderRadius: '10px' }} src={image} alt={description} /> <div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'center', width: '80%', gap: '10px', }} > <p style={{ fontSize: '16px', fontWeight: 'bold', color: 'black' }}> {title} </p> <p style={{ fontSize: '16px', fontWeight: 'bold', color: 'gray' }}> {description} </p> </div> <div style={{ display: 'flex', gap: '10px' }}> <LinkIconBtn link={link} /> <HeartIconBtn isFavorite={isFavorite} /> </div> </div> </> ); }CourseItem 컴포넌트에서 LinkIconBtn 을 포함하고 있습니다. LinkIconBtn 컴포넌트에서 function LinkIconBtn({ link }) { return ( <> {link ? ( <a href={link} target="_blank"> <img style={{ width: '36px' }} src="/images/link-icon.svg" alt="lecture link" /> </a> ) : null} </> ); }위 처럼 Fragment 를 사용하거나 <div></div> 를 사용해서 wrapping 을 하지 않으니깐 아래 처럼 오류가 발생하는데 이유를 정확하게 모르겠습니다...
-
미해결React 완벽 마스터: 기초 개념부터 린캔버스 프로젝트까지
[수정] 린캔버스 수정1만 자막 없습니다.
안녕하세요~! 지금까지 수업 진도 잘 따라갔는데 [수정] 린캔버스 수정1만 자막이 없네요 ㅠㅠ 자막 언제 나올까요?
-
미해결React 완벽 마스터: 기초 개념부터 린캔버스 프로젝트까지
eslint를 추가하였지만 동작을 안합니다.
'react/self-closing-comp': 'warn' 해당 문구를 추가했음에도 동작하지 않습니다. 재부팅도 해보았습니다만 동작하지 않습니다.제가 잘못한 것이 있을까요?
-
미해결React 완벽 마스터: 기초 개념부터 린캔버스 프로젝트까지
개발 서버가 실행 안 되는 문제
npm install 설치한 뒤 개발 서버 키기 위해서 npm run dev 입력했는데 이런 에러가 뜹니다.인터넷 찾아 본 결과 npm install watchman 이거 해줘야 에러 안 나는 거 알고 있지만, 번번이 프로젝트 생성할 때마다 이런 에러가 꼭 뜹니다. 혹시 해결 방법이 있을까요?
-
미해결React 완벽 마스터: 기초 개념부터 린캔버스 프로젝트까지
assets과 public의 차이점
assets에 있는 파일이 번들링이 된다면 assets에 이미지같은것들을 넣으면 될까요???public에있는 파일들은 '최종번들에 복사되어진다'고 하셨는데 이말이 무슨뜻인지 잘이해가 안가서그러는데 부가설명해주시면 감사하겠습니다.
-
해결됨[React 2부] 고급 주제와 훅
MyReact를 IIFE(즉시실행함수)로 설계하신 이유
제목그대로, MyReact를 IIFE(즉시실행함수)로 설계하신 이유가 무엇일까요???이걸 끌어다 쓰는 곳에서MyReact.creacteContext()MyReact().createContext() 이렇게 쓰는것이 아니라, 위의 코드처럼 쓰려고 그런것일까요????
-
해결됨[React 2부] 고급 주제와 훅
[4.4장 메모이제이션 훅] 4.4.3 memo 참조 비교
안녕하세요. 강사님! 학습 중에 궁금한 점이 생겼는데, 제가 이해하고 있는 내용이 맞는지 궁금해 질문 드립니다!const obj1 = { a: 1 }; const obj2 = { a: 1 }; const obj3 = obj1; console.log(obj1 === obj2); // falseconsole.log(obj1 === obj3); // true 자바스크립트에서 객체나 배열을 비교할 때 기본적으로 참조를 비교하는 것으로 알고 있습니다. 즉, 1번에서 두 객체가 같은 값을 가지고 있으나 메모리 주소가 달라 false를 출력하고,2번에선 같은 메모리 주소를 참조해 true를 출력하는 것으로 알고 있습니다여기서부터 제가 궁금했던 내용입니다!캐시된 filteredPosts를 사용해 렌더링하는 경우를 가정했을 때 :const filteredPosts = MyReact.useMemo(filterPosts, [posts, tag]);filteredPosts는 useMemo를 통해 filterPosts 함수로 생성된 배열을 클로저 공간에 넣어두고, posts와 tag가 변경되지 않는다면 항상 똑같은 값을 FilteredPosts로 전달 =><FilteredPosts posts={filteredPosts} /> const FilteredPosts = MyReact.memo(({ posts }) => { ... } // FilteredPosts는 캐시된 filteredPosts를 memo 함수로 전달 =>function memo(TargetComponent) { return (nextProps) => { ... const [prevValue, prevProps] = TargetComponenet.memorizedState; if (prevProps === nextProps) { return prevValue; } ... } }그럼 여기 전달된 nextProps(캐시된 filteredProps)는 당연히 같은 메모리를 참조하니 깊은 비교 없이 참조 비교만으로도 비교가 가능하지 않나? 싶었습니다.filteredPosts는 결과적으로 useMemo로 캐시되어있고, 새로 생성된 배열이 아니니 메모리 주소가 동일해 prevValue가 리턴되지 않을까? 했는데 아니더라구요..useMemo를 통해 filteredPosts 배열의 참조는 동일하게 유지되고 있는건 맞는데,{ posts: filteredPosts }이렇게 FilteredPosts 컴포넌트에 전달되는 props 객체가 매번 새로운 객체로 생성돼서 그런건가? 싶은데 이게 맞는지 궁금해서 질문 드립니다..
-
미해결React 완벽 마스터: 기초 개념부터 린캔버스 프로젝트까지
조건부 렌더링중 &&와 버튼 3항 연산자가 화면처럼 안나오네요ㅠㅠ
CoursItem.jsxApp.jsx제 개발화면확인 부탁드립니다:)