묻고 답해요
141만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨[2024] 한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
2.13) 비동기 작업 처리하기 2. Promise
promise 객체를 어떻게 사용하는건지 배웠는데요콜백지옥을 해결하기 위해 탄생한건가요?promise 객체를 사용해서 비동기함수를 쓰면 얻는 장점이 무엇인가요? 결과적으로 얻는 이점에 대한 설명이 좀 부족하지 않나 싶고 궁금합니다
-
해결됨[2024] 한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
버전 문제일까요?
안녕하세요 4분 45초에ReactDom.create 이렇게 되어있는데 저의 경우createRoot(document.ge로 시작합니다. 구글에 찾아보니 17과 18의 차이라는데https://velog.io/@citron03/React-18%EC%97%90%EC%84%9C-ReactDOM.render%EC%99%80-createRoot그대로 진행해도 문제되지 않을까여 ? 감사합니다.
-
미해결[2024] 비전공자도 가능한 React Native 앱 개발 마스터클래스
프로젝트 생성에 대해서?
npx react-native init test --version 0.72.6 Expo 아니라면 이렇게 생성해야 하는 거 아닌지요?
-
해결됨[2024] 한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
12.11) Home 페이지 구현하기 2.기능 - 버튼 기능 질문
안녕하세요 강사님!12.11) Home 페이지 구현하기 2.기능 강의에서,getMonth( ) 함수는 월이 0부터 시작된다고 말씀하셨습니다. 따라서 아래 코드처럼 Header 컴포넌트에 title의 props 값으로 +1을 하여 전달해야 한다는 것을 이해했습니다. <Header title={`${pivoDate.getFullYear()}년 ${pivoDate.getMonth() + 1}월`} leftChild={<Button text={"<"} onClick={onDecreaseMonth} />} rightChild={<Button text={">"} onClick={onIncreaseMonth} />} /> 그런데 버튼을 누르면 저번 달, 다음 달로 이동하는 함수를 만들 땐 getMonth( ) 함수를 불러오고 각각 1을 더하거나 빼는 함수로 설정한 점이 이해가 가지 않습니다. 0월부터 시작하기 때문에 각각 2를 더하거나 빼야 한다고 생각했는데 왜 1을 더하고 빼는지 모르겠습니다. ㅠㅠ const onIncreaseMonth = () => { setPivoDate(new Date(pivoDate.getFullYear(), pivoDate.getMonth() + 1)); }; const onDecreaseMonth = () => { setPivoDate(new Date(pivoDate.getFullYear(), pivoDate.getMonth() - 1)); }; 항상 좋은 강의 만들어주셔서 감사합니다!
-
해결됨[2024] 한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
sort 콜백함수
강의 2.9 ) 배열 메서드 3.배열 변형11분이후 sort에 콜백함수에서 조건문으로 return 1을 반환하면두 자리를 교환하는걸로 이해했는데요 -1을 반환하면자리 교환이 일어나지 않는것 같구요 0을 반환했을때랑차이점이 있나요??
-
해결됨[2024] 한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
날짜 비교 방법에 관해서 문의드립니다.
안녕하세요 이정환님!! 강의 잘듣고 있습니다. 12.11) Home 페이지 구현하기 2. 기능 강의 수강중에 궁금한 점이 생겨 문의드립니다.두개의 날짜를 정보를 비교를 하기 위해서는 Date의 객체 형식을 timestamp 형식으로 변경을 한후 두개의 날짜 정보를 비교를 해야 하는 것으로 알고 있습니다.강의에서 pivotDate에 저장이 되어있는 state 날짜 기준으로 data를 필터링 하기 위해서는 시작시간과 끝시간을 timestamp 형식으로 만들고 시작시간과 끝시간 사이에 있는 data 객체 안에 있는 createDate의 값을 필터링 하셨습니다.여기서 궁금한점이 startDate와 endDate 변수에는 timestamp형식의 날짜 정보가 들어가 있지만 data.createDate 정보에는 객체형태의 날짜 정보가 들어가 있습니다. 어떻게 객체 형태의 날짜 정보와 timestamp 형식의 날짜 정보가 비교가 가능한지 궁금합니다.제가 어떤 부분에서 착각을 하고 있는지 궁금합니다. 감사합니다.^^
-
해결됨[2024] 한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
수정페이지의 작성완료 누를떄 에러가 납니다
Edit 페이지 구현하기 챕터의 작성완료 누를때 에러가 나는데 이유를 모르겠어요https://github.com/dajungleee/section12 확인 한번 부탁드려요ㅠㅠ
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
섹션16 husky
git도 다운받았고 터미널도 git bash가 작동이 됩니다.근데 husky 다운이 안되네요. .git can't be found 따라하는데 계속 이 문장만 자꾸 뜹니다.그래서 인강에 나온 방법처럼 하지 않고 학습자료에 나와있는거 처럼 따라했는데 괜찮나요?학습자료 방법으로 해도 괜찮나요 추가 질문) git 을 계속 재설치해서 husky를 깔아도 .git can't be found만 뜨는데요. 왜그런걸까요
-
해결됨[2024] 한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
Vscode 한글 설정이 잘 안되요
다음처럼 설정이나 이런 곳에는 한글 적용이 잘 되는데Error lens 플러그인 설치 후 에러 알려주는 부분에서는 영어로만 됩니다.!
-
미해결프론트엔드 개발환경의 이해와 실습 (webpack, babel, eslint..)
webpack에서 babel-loader 사용할때 질문
babel-loader 만 webpack.config.js에 설정하면 제가 적었던 babel.config.js는 저절로 인식이되는것인가요?
-
미해결[개정3판] Node.js 교과서 - 기본부터 프로젝트 실습까지
팔로잉과 팔로워 관계
deserializeUser에서 req.user에 넣을 팔로잉이랑 팔로워 찾으실 때, as는 모델 관계의 as를 따라간다고 하셨는데 왜 위 코드에서 Follwers가 //팔로잉이고 Followings가 //팔로워라고 하신 건지 모르겠습니다ㅜ 예를 들어, 저의 팔로잉을 찾으려면 제 아이디를 팔로워 아이디에서 찾아야 하니까 기준 아이디가 followerId가 되는 Followings가 맞는거 아닌가요?
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 챗봇 사이트 만들기
이벤트 쿼리문제입니다
포스트맨에서는 이벤트 쿼리가 답이 옵니다. http://localhost:3000/api/dialogflow/eventQueryhttp://localhost:5000/api/dialogflow/eventQuery 둘다 답이 옵니다. 다만 터미널과 아래 처럼 브라우저에서 인사말이 오지 않습니다. 시작하면 처음에 이벤트쿼리문이 오게 하려면 어떻게 해야하나요?메번 감사합니다
-
해결됨[개정3판] Node.js 교과서 - 기본부터 프로젝트 실습까지
nodebird 프로필 수정 기능 구현 시, 에러가 발생했을 때 에러처리미들웨어에서 res.render('error')가 안되는 상황
프로필 수정 기능을 구현하기 위한 profileUpdate.html{% extends 'layout.html' %} {% block content %} <div class="timeline"> <form id="profile-update-form"> <!-- <div class="input-group"> <label for="join-email">이메일</label> <input id="join-email" type="email" name="email" /> </div> --> <div class="input-group"> <label for="join-nick">닉네임</label> <input id="join-nick" type="text" name="nick" /> </div> <div class="input-group"> <label for="join-password">비밀번호</label> <input id="join-password" type="password" name="password" /> </div> <button id="join-btn" type="submit" class="btn">수정</button> </form> </div> {% endblock %} {% block script %} <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script> window.onload = () => { const errorParam = new URL(location.href).searchParams.get('error'); if (errorParam) { alert(errorParam); } }; if (document.getElementById('profile-update-form')) { document.addEventListener('submit', async (event) => { event.preventDefault(); const formData = new FormData(event.target); const config = { headers: { 'content-type': 'application/json', }, }; axios .put('/profile/update', formData, config) .then((res) => { alert('프로필 정보가 수정되었습니다.'); window.location.href = '/profile'; }) .catch((error) => { alert(error); }); }); } </script> {% endblock %} 그리고 controller/page.jsexports.renderProfileUpdate = (req, res, next) => { res.render('profileUpdate', { title: '내 정보 수정 - NodeBird' }); }; exports.profileUpdate = async (req, res, next) => { try { const { nick, password } = req.body; const id = req.user.id; const exUser = await User.findOne({ where: { id } }); if (!exUser) { throw new Error('존재하지 않는 사용자입니다.'); // res.status(404).send('no user'); } const sameNickUser = await User.findOne({ where: { nick, id: { [Op.ne]: exUser.id, }, }, }); if (sameNickUser) { throw new Error('중복된 닉네임입니다.'); // res.status(501).send('중복된 닉네임입니다.'); } const hash = await bcrypt.hash(password, 12); exUser.set({ nick, password: hash, }); await exUser.save(); res.status(201).send(); } catch (error) { console.error(error); next(error); } };app.js의 에러처리 미들웨어app.use((err, req, res, next) => { // 404 다음은 에러처리 미들웨어 console.error('에러는 ', err.message); res.locals.message = err.message; res.locals.error = process.env.NODE_ENV !== 'production' ? err : {}; // 보안상 위험(오히려 배포 시 사용자 화면에 에러를 숨김) // 에러를 로깅 서비스에 넘김 res.status(err.status | 500); res.render('error'); // views/error.html });일부러 중복된 닉네임을 넣어 라우터에서 에러를 발생시켰을 때, 에러처리미들웨어의 console.error('에러는 ', err.message); 부분에서 "Error: 중복된 닉네임입니다. at exports.profileUpdate (/nodestudy/nodebird/controllers/page.js:31:13) at process.processTicksAndRejections (node:internal/process/task_queues:95:5)에러는 중복된 닉네임입니다.PUT /profile/update 500 10.568 ms - 1862" 로 에러 메시지가 정상적으로 찍히는 것을 확인하였습니다.preview 탭에선 정상적으로 나오는 것 같은데, 실제 브라우저 화면에선 위와 같이 뜨면서 제가 원하는 에러 메시지('중복된 닉네임입니다')가 alert 창에 뜨지 않으며, error.html이 렌더링도 되지 않고 있습니다. 구글링해봐도 제가 잘 못한건지 이유를 못찾겠습니다🥲 제가 뭘 놓친걸까요?
-
미해결[개정3판] Node.js 교과서 - 기본부터 프로젝트 실습까지
connect.sid를 쿠키에 넣는 시점과 express-session
req.login를 통해 req.session에 { 랜덤값: 유저아이디}를 저장하는 건 알겟는데, connect.sid=랜덤값을 쿠키에 넣는 시점은 언제인가요?그리고 서버가 connect.sid를 세션 쿠키로 전송할 때, express-session 은 자동으로 이 값을 secret으로 서명하여 전송하나요?
-
미해결프론트엔드 개발환경의 이해와 실습 (webpack, babel, eslint..)
자주 사용하는 플러그인 에서 질문이 있습니다.
new HtmlWebpackPlugin({ template: "./src/index.html", templateParameters: { env: process.env.NODE_ENV === "development" ? "(개발용)" : "" }, minify: process.env.NODE_ENV === "production" ? { collapseWhitespace: true, removeComments: true, } : false }), new CleanWebpackPlugin({ }), ...(process.env.NODE_ENV === "production" ? [new MiniCssExtractPlugin({filename: "[name].css"})] : []) ]왜 MiniCssExtractPlugin에서는 spread operator를 쓰고 삼항연산자를 쓴 건가요? 위에 HtmlWebpackPlugin에서 한것처럼 그냥 process.env.NODE_ENV 삼항연산자를 쓰면 되는게 아닌가요?추가적으로 spread operator를 쓴 이유를 알고 싶습니다!!
-
미해결[2024] 비전공자도 가능한 React Native 앱 개발 마스터클래스
설치 관련 질문
npx create-react-native-app@latest 요거 터미널에 입력하니까, ⚠ This tool does not initialize new React Native projects. 뜨는데, 어떻게 해결하면 좋을까요?
-
미해결프론트엔드 개발환경의 이해와 실습 (webpack, babel, eslint..)
eslint no-extra-semi 관련 질문
안녕하세요. eslint 강의를 듣고 있습니다. 답변해주시면 감사하겠습니다!버전은 아래와 같습니다."@eslint/js": "^9.9.1", "@stylistic/eslint-plugin-js": "^2.6.4", "webpack": "^5.93.0", "webpack-cli": "^5.1.4" eslint 공식홈에 no-extra-semi 사용법을 확인하면 아래와 같이 나와있습니다.https://eslint.org/docs/latest/rules/no-extra-semi#rule-detailsThis rule was deprecated in ESLint v8.53.0. Please use the corresponding rule in @stylistic/eslint-plugin-js.8.53.0 버전부터 deprecated가 되어서 stylistic 플러그인을 사용해서 쓰라고 되어 있습니다. 그래서 아래와 같이 설정을 했습니다.// eslint.config.js import js from "@eslint/js"; import stylisticJs from '@stylistic/eslint-plugin-js' export default [ js.configs.recommended, { plugins: { '@stylistic/js': stylisticJs, }, } ];그런데, no-extra-semi rule이 동작을 하지 않고 아래와 같이 rules안에 명시를 해줘야만 동작을 합니다. 플러그인만 명시하면 되는게 아니라 사용할 rule을 하나하나 명시해줘야만 하는건가요?// eslint.config.js import js from "@eslint/js"; import stylisticJs from '@stylistic/eslint-plugin-js' export default [ js.configs.recommended, { plugins: { '@stylistic/js': stylisticJs, }, rules: { "@stylistic/js/no-extra-semi": "error" } } ]; 그리고 추가적으로 궁금한 것은 deprecated 되었다고 했는데 왜 아래와 같이 eslint에서 "no-extra-semi" 를 사용할 수 있는걸까요?// eslint.config.js import js from "@eslint/js"; import stylisticJs from '@stylistic/eslint-plugin-js' export default [ js.configs.recommended, { rules: { "no-extra-semi": "error" } } ];
-
미해결[2024] 한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
Context 분리 질문
Context를 이용하여 props를 분리하고, onUpdate, onCreate같이 한번만 수행되는 함수들은 useMemo를 이용하여 메모이제이션을 한다고 했습니다. 아래 코드처럼요 const memoDispatch = useMemo(() => { return { onCreate, onUpdate, onDelete, }; }, []);그런데 이전 시간에 각각의 함수를 useCallback를 통해 메모이제이션 했는데 한번 더 하는 이유가 이해 가지 않아 질문 드립니다. 아래 코드처럼 useCallback를 통해 처음 렌더링 될 때만 실행되고 이후에는 실행되지 않도록 코드를 작성 했는데 맨 위의 코드처럼 한번 더 감싼? 이유가 잘 이해가 되지 않습니다.const onCreate = useCallback((content) => { dispatch({ type: "CREATE", data: { id: idRef.current++, isDone: false, content: content, date: new Date().getTime(), }, }); }, []); const onUpdate = useCallback((targetId) => { dispatch({ type: "UPDATE", targetId: targetId, }); }, []); const onDelete = useCallback((targetId) => { dispatch({ type: "DELETE", targetId: targetId, }); }, []);
-
해결됨[2024] 한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
자식 컴포넌트 리렌더링
자식 컴포넌트 Bulb와 Counter를 해당 강의에서 분리했는데 다음과 같은 의문이 생겼습니다. 이렇게 분리했더라도 결국 Counter의 state가 변경되면서 Counter가 리렌더링 되는 걸로 알고 있습니다. 이러한 경우 부모 컴포넌트인 App도 리렌더링되면서 Bulb 컴포넌트도 리렌더링되는 것 아닌가요?
-
미해결[2024] 비전공자도 가능한 React Native 앱 개발 마스터클래스
expo로 설치해도 되나요?
npx create-expo-app@latest 이렇게 설치했는데 강의랑 설치하는게 다르고 폴더구성도 다르더라구요