묻고 답해요
130만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 레딧 사이트 만들기(NextJS)(Pages Router)
강사님 이 코드에서 백틱과 따옴표들이요..
const subs = await AppDataSource.createQueryBuilder() .select( `s.title,s.name,${imageUrlExp} as "imageUrl", count(p.id) as "postCount"` ) .from(Sub, 's') .leftJoin(Post, 'p', `s.name = p."subName"`) .groupBy('s.title, s.name, "imageUrl"') .orderBy(`"postCount"`, 'DESC') .limit(5) .execute(); 위의 코드에서 백틱 ``과 따옴표들 '', "" 사용방식들에대한 기초적인 지식을 쌓으려면 어떻게 검색해보면될까요?일단 제 나름대로 접근식으로는 .from이나 .orderBy 이런건 typeORM 문법인거같아서 찾아보니 문서에는 백틱은 안적혀있는거같고 따옴표로만 작성해준거같아서요.. 혹시 변수가 들어가있으면 ``를써주는게맞나요?근데 .orderBy부분에서 `"postCount"`, 이부분이 좀 이해가 안가는게 백틱에 또 큰따옴표를 감싸주셔서..
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 레딧 사이트 만들기(NextJS)(Pages Router)
강사님 req.header.cookie에 언제 쿠키를 담아줬는지 궁금합니다.
export const getServerSideProps: GetServerSideProps = async ({ req, res }) => { try { const cookie = req.headers.cookie; console.log(req.headers.cookie); // 쿠키가 없다면 에러를 보냄 if (!cookie) throw new Error('Missing auth token cookie'); // 쿠키가 있다면 그 쿠키를 이용해서 백엔드에서 인증 처리하기 await axios.get('/auth/me', { headers: { cookie } }); return { props: {} }; } catch (error) { // 백엔드에서 요청에서 던져준 쿠키를 이용해 인증 처리할 때 에러가 나면 // login 페이지로 이동 res.writeHead(307, { Location: '/login' }).end(); return { props: {} }; } }; axios.get에 파라미터로 헤더.쿠키 로 넣어준걸까요?근데 순서대로 코드가 동작하게되면 if문에 걸려서 영원히 쿠키가 없어 페이지가 로그인페이지로 이동될텐데 제가 잘못생각한걸까요?두번쨰로 리턴 props:{}로 해주신 이유에대해서 궁금합니다. 다른식으로 그냥 return; 이렇게 작성하고 끝내도 괜찮을까요?
-
해결됨따라하며 배우는 리액트 A-Z
에러 질문드립니다
next13 학습을 진행하고 있는데 오류가 발생해서 질문드립니다.기본적으로이 상태에서는이런 오류가 발생하고<Link>를 사용을 하게 되면이런 오류가 발생합니다..어떻게 해야하나요?
-
미해결Slack 클론 코딩[실시간 채팅 with React]
swr revalidate에 대해 질문드립니다.
안녕하세요 swr revalidate 가 deprecated 되어 mutate를 사용하면 된다는 답변을 확인하고 mutate를 썼는데 궁금한 점이 있습니다. mutate()를 하는 이유는 로그인 성공했을때 그 시점에 users api를 호출하기 위해서 인가요?그리고 mutate 와 무관하게 디폴트 설정에따라(화면전환등) SWR에서 userapi를 호출하고 있는것도 맞나요?1: 화면 첫 렌더링때 user api 콜로그인mutate실행으로 user api 콜화면전환했을때 다시 콜 제가 이해한게 맞는지 답변 부탁드립니다.감사합니다.
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 레딧 사이트 만들기(NextJS)(Pages Router)
배포는되는데 회원가입부터 오류가 막뜹니다
안녕하세요 선생님첫화면엔 커넥션 리퓨즈 뜨고회원가입 누르면 이러한 오류가 뜹니다 넘어가질 않고 오류가 계속나오는데 왜이런걸까요?..무엇이 문제인지 궁금합니다:4000 으로 계속 찍히는거 보면 cors가 안되는것일까요강의보고 다 제대로 따라했는데 ㅠㅠ도와주시면 감사하겠습니다
-
미해결따라하며 배우는 리액트 A-Z
에러 문의 react hook useEffect
src/components/Row.js Line 14:7: React Hook useEffect has a missing dependency: 'fetchMovieData'. Either include it or remove the dependency array react-hooks/exhaustive-deps쌤 그리고 fetchMovieData 가 있습니다. 그것을 포함하거나 종속성 배열 React-hooks/exhausitve deps를 제거하라는게 무슨말인가요??
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 레딧 사이트 만들기(NextJS)(Pages Router)
선생님 삭제기능은 어떤식으로 해야될까요
선생님 포스트 나 댓글 삭제기능은 어떤식으로 해야될까요 따로 강의는 없겟죠? ㅠ
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 레딧 사이트 만들기(NextJS)(Pages Router)
post 타이틀을 한글로 쓰면 경로이동이 안됩니다
안녕하세요 선생님post 타이틀을 한글로 쓰면 경로이동이 안됩니다 영어로 쓰면 라우터대로 경로가 이동하는데 한글로 쓰면 이동이 안되네요... 왜이럴까요 한글타이틀 도 영어타이틀 처럼 잘 이동될순 없을까요
-
미해결Slack 클론 코딩[실시간 채팅 with React]
회원가입 요청이 가지않는 이슈
회원가입을 눌렀으나 회원가입이 안되고 요청이 가지 않는 것 같습니다. 에러메세지를 긁어서 확인 해보았으나 어디가 잘못된건지 모르겠고, 서버 부분의 콘솔을 확인해 보았으나 에러메세지가 나오지 않았습니다. 에러 메세지 이미지와 본문입니다.react_devtools_backend.js:4012 Error: Minified React error #31; visit https://reactjs.org/docs/error-decoder.html?invariant=31&args[]=object%20with%20keys%20%7Bsuccess%2C%20code%2C%20data%7D for the full message or use the non-minified dev environment for full errors and additional helpful warnings. at ka (react-dom.production.min.js:140:47) at react-dom.production.min.js:150:265 at Ml (react-dom.production.min.js:176:171) at Bi (react-dom.production.min.js:271:134) at Eu (react-dom.production.min.js:250:347) at wu (react-dom.production.min.js:250:278) at bu (react-dom.production.min.js:250:138) at pu (react-dom.production.min.js:243:163) at react-dom.production.min.js:123:115 at t.unstable_runWithPriority (scheduler.production.min.js:18:34 혹시나 ENV를 까먹었을까봐 다시 확인했지만 있었고,아래는 서버쪽 터미널 이미지입니다.감사합니다.
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 레딧 사이트 만들기(NextJS)(Pages Router)
comment 삭제하는법
배포하기 전에 커뮤니티, 포스트, comment 삭제하고 다시작성하고 싶은데 어떻게해야될까요?
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 레딧 사이트 만들기(NextJS)(Pages Router)
로그인 시도 시 타입에러 나는데 모르겠네요
TypeError: dispatch is not a functionat handleSubmit (login.tsx?11e1:23:13) 에러나는 부분은login파일의 dispatch("LOGIN",res.data?.user); 에서 에러가 납니다. 이 강의 듣는 몇몇분들도 동일하게 나타나는 증상같은데.. 확인 한번 부탁드립니다.
-
미해결[리뉴얼] 타입스크립트 올인원 : Part2. 실전 분석편
안녕하세요 제로초님 질문있습니다!
안녕하세요. 제로초님 저는 redux toolkit으로 axios error처리 하려고 합니다!. 플로우는 createAsyncThunk에서 login액션으로 왔을 때 catch로 error를 잡아준 뒤 reducer에서 .addCase(login.rejected, (state, action: PayloadAction<any>) => { state.loginError = action.payload; })loginError로 에러 메시지가 들어오게 하는것입니다.먼저catch에서는 export const login = createAsyncThunk( ... } catch (error) { if (axios.isAxiosError(error)) { console.error((error as AxiosError<{message: string}>).response?.data.message) } return rejectWithValue(error.message); << Object is of type 'unknown'. } 강의대로 요렇게 해주었는데 rejectWithValue에서이러한 경고문이 발생합니다.또한 reducer에서interface InitialState { loginError: string | null; } const initialState: InitialState = { loginError: null, }; const userSlice = createSlice({ ... .addCase(login.rejected, (state, action: PayloadAction<any>) => { state.loginError = action.payload; })이부분에서InitialState에서 loginError는 어떠한 에러 타입을 지정해주어야 하며 login.rejected에서 에러가 들어올 경우 PayloadAction에는 어떠한 타입을 지정해주어야 하는지 궁금합니다! 즉 return rejectWithValue(error.message);에서는 어떻게 error.message를 보내주어야 하며 reducer에서 loginError에는 어떠한 초기값을 설정하고payloadAction에서도 어떠한 타입을 지정해주어야 하는지 궁금합니다!
-
미해결따라하며 배우는 리액트 A-Z
s3 배포시 Re-run all jobs 버튼 부재
Re-run all jobs 버튼이 없어서 node.js에서 오류가 발생하는데 혹시 어떻게 해야할까요?
-
미해결Slack 클론 코딩[실시간 채팅 with React]
채널 생성시 channelData.map is not a function
채널생성 클릭하면 channeldata.map is not a function이라고 에러가 뜨는데channelData뿌려지는곳에 ?옵셔널도 줬고..아래처럼 잘 작성한것같은데 어딜 놓쳤는지 모르겠습니다.새로고침하면 추가된 채널명이 출력됩니다. workspaceimport fetcher from '@utils/fetcher'; import axios from 'axios'; import React, { FC, useCallback, useState } from 'react'; import { Navigate, useParams } from 'react-router-dom'; import useSWR from 'swr'; import { AddButton, Channels, Chats, Header, LogOutButton, MenuScroll, ProfileImg, ProfileModal, RightMenu, WorkspaceButton, WorkspaceModal, WorkspaceName, Workspaces, WorkspaceWrapper, } from './styles'; import gravatar from 'gravatar'; import Menu from '@components/menu'; import { Link } from 'react-router-dom'; import { IChannel, IUser, IWorkspace } from '@typings/db'; import { Button, Input, Label } from '@pages/signup/styles'; import useInput from '@hooks/useInput'; import Modal from '@components/modal'; import { toast } from 'react-toastify'; import CreateChannelModal from '@components/createChannelModal'; const Workspace: FC = ({ children }) => { const { workspace, channel } = useParams<{ workspace: string; channel: string }>(); const { data: userData, error, mutate } = useSWR<IUser | false>('/api/users', fetcher, { dedupingInterval: 2000 }); const { data: channelData } = useSWR<IChannel[]>(userData ? `/api/workspaces/${workspace}/channels` : null, fetcher); if (!userData) { return <Navigate to="/login" />; } const [showUserMenu, setShowUserMenu] = useState(false); const [newWorkspace, onChangeNewWorkspace, setNewWorkspace] = useInput(''); const [newUrl, onChangeNewUrl, setNewUrl] = useInput(''); const [showWorkspaceModal, setShowWorkspaceModal] = useState(false); const [showCreateChannelModal, setShowCreateChannelModal] = useState(false); const [showCreateWorkspaceModal, setShowCreateWorkspaceModal] = useState(false); //functions const onLogout = useCallback(() => { axios .post('/api/users/logout', null, { withCredentials: true, }) .then((res) => { mutate(res.data); }); }, []); const onClickUserProfile = useCallback(() => { setShowUserMenu(!showUserMenu); }, [showUserMenu]); const onClickCreateWorkspace = useCallback(() => { setShowCreateWorkspaceModal(true); }, []); const onCreateWorkspace = useCallback( (e) => { e.preventDefault(); if (!newWorkspace || !newWorkspace.trim()) return; if (!newUrl || !newUrl.trim()) return; //trim ->띄어쓰기 하나도 통과 돼버리는걸 막는다. axios .post( '/api/workspaces', { workspace: newWorkspace, url: newUrl, }, { withCredentials: true, }, ) .then((res) => { mutate(res.data); setShowCreateWorkspaceModal(false); setNewWorkspace(''), setNewUrl(''); }) .catch((err) => { console.dir(err); toast.error(error.response?.data, { position: 'bottom-center' }); }); }, [newWorkspace, newUrl], ); const onCloseModal = useCallback(() => { setShowCreateWorkspaceModal(false); setShowCreateChannelModal(false); }, []); const toggleWorkspaceModal = useCallback(() => { setShowWorkspaceModal(!showWorkspaceModal); }, [showWorkspaceModal]); const onClickAddChannel = useCallback(() => { setShowCreateChannelModal(true); }, []); return ( <div> <Header> <RightMenu> <span onClick={onClickUserProfile}> <ProfileImg src={gravatar.url(userData.email, { s: '28px', d: 'retro' })} alt={userData.nickname} /> {showUserMenu && ( <Menu style={{ right: 0, top: 38 }} onCloseModal={onClickUserProfile} show={showUserMenu}> <ProfileModal> <img src={gravatar.url(userData.email, { s: '28px', d: 'retro' })} alt={userData.nickname} /> <div> <span id="profile-name">{userData.nickname}</span> <span id="profile-active">Active</span> </div> </ProfileModal> <LogOutButton onClick={onLogout}>로그아웃</LogOutButton> </Menu> )} </span> </RightMenu> </Header> <WorkspaceWrapper> <Workspaces> {userData.Workspaces?.map((ws: IWorkspace) => { return ( <Link key={ws.id} to={`/workspace/${123}/channel/일반`}> <WorkspaceButton>{ws.name.slice(0, 1).toUpperCase()}</WorkspaceButton> </Link> ); })} <AddButton onClick={onClickCreateWorkspace}>+</AddButton> </Workspaces> <Channels> <WorkspaceName onClick={toggleWorkspaceModal}>Sleact</WorkspaceName> <MenuScroll> <Menu show={showWorkspaceModal} onCloseModal={toggleWorkspaceModal} style={{ top: 95, left: 80 }}> <WorkspaceModal> <h2>Sleact</h2> {/* <button onClick={onClickInviteWorkspace}>워크스페이스에 사용자 초대</button> */} <button onClick={onClickAddChannel}>채널 만들기</button> <button onClick={onLogout}>로그아웃</button> </WorkspaceModal> </Menu> {channelData?.map((v, idx) => ( <div key={idx}>{v.name}</div> ))} </MenuScroll> </Channels> <Chats> {children}</Chats> </WorkspaceWrapper> <Modal show={showCreateWorkspaceModal} onCloseModal={onCloseModal}> <form onSubmit={onCreateWorkspace}> <Label id="workspace-label"> <span>워크스페이스 이름</span> <Input id="workspace" value={newWorkspace} onChange={onChangeNewWorkspace} /> </Label> <Label id="workspace-url-label"> <span>워크스페이스 url</span> <Input id="workspace" value={newUrl} onChange={onChangeNewUrl} /> </Label> <Button type="submit">생성하기</Button> </form> </Modal> <CreateChannelModal show={showCreateChannelModal} onCloseModal={onCloseModal} setShowCreateChannelModal={setShowCreateChannelModal} /> </div> ); }; export default Workspace; createChannelModalimport Modal from '@components/modal'; import useInput from '@hooks/useInput'; import { Button, Input, Label } from '@pages/signup/styles'; import { IChannel, IUser } from '@typings/db'; import fetcher from '@utils/fetcher'; import axios from 'axios'; import React, { useCallback, VFC } from 'react'; import { useParams } from 'react-router-dom'; import { toast } from 'react-toastify'; import useSWR from 'swr'; interface Props { show: boolean; onCloseModal: () => void; setShowCreateChannelModal: (flag: boolean) => void; } const CreateChannelModal: VFC<Props> = ({ show, onCloseModal, setShowCreateChannelModal }) => { const [newChannel, onChangeNewChannel, setNewChannel] = useInput(''); const { workspace, channel } = useParams<{ workspace: string; channel: string }>(); const { data: userData } = useSWR<IUser | false>(`/api/users`, fetcher); const { data: channelData, mutate } = useSWR<IChannel[]>( userData ? `/api/workspaces/${workspace}/channels` : null, fetcher, ); const onCreateChannel = useCallback( (e) => { e.preventDefault(); axios .post( `/api/workspaces/${workspace}/channels`, { name: newChannel, }, { withCredentials: true }, ) .then((res) => { setShowCreateChannelModal(false); mutate(res.data); setNewChannel(''); }) .catch((err) => { console.dir(err); toast.error(err.response?.data, { position: 'bottom-center' }); }); }, [newChannel], ); return ( <Modal show={show} onCloseModal={onCloseModal}> <form onSubmit={onCreateChannel}> <Label id="channel-label"> <span>채널</span> <Input id="channel" value={newChannel} onChange={onChangeNewChannel} /> </Label> <Button type="submit">생성하기</Button> </form> </Modal> ); }; export default CreateChannelModal;
-
미해결따라하며 배우는 NestJS
nested json을 dto로 전달하려면 어떻게 해야하나요?
1개의 json 객체 안에 프로퍼티가 다른 여러 객체들이 들어있는 리스트가 담겨있는 것을 dto로 전달하려면 어떻게 해야하나요?구글링해보니까 nested 인터페이스를 사용하기도 하던데,Entity는 일반적으로 class로 만드니까 nested class는 어떻게 생성하는지가 궁금합니다.그리고 제 목표는 저 json 인에 들어있는 2가지 종류의 객체( slider type과 selecrive type)를 1번의 post메소드로만 보내고 싶습니다. 그런데 아래처럼 두 객체의 프로퍼티가 다를때, 하나의service,controller,repository를 이용해서 전달하려면 어떻게 해야하나요?json 객체의 형태는 아래와 같습니다.{ "questions_count": 8, "results_slider": [ { "type": "slider", "main_criteria_id": 0, "main_criteria": "Mollit mollit qui sint irure do ad laborum quis ullamco eu dolor.", "sub_criterias": [ "Eu occaecat pariatur sunt duis amet in sint velit amet consequat deserunt.", "Culpa Lorem nisi ut ea irure et eu do cupidatat ipsum duis veniam elit." ], "results": [ { "sub_criteria_id": 0, "sub_criteria_score": 4.7748 }, { "sub_criteria_id": 1, "sub_criteria_score": 7.091 } ] }, { "type": "slider", "main_criteria_id": 1, "main_criteria": "Qui consequat ullamco aliquip Lorem minim commodo irure magna cillum.", "sub_criterias": [ "Velit eu ullamco id nisi quis consequat non non commodo aliquip qui mollit.", "In esse amet proident dolore do aliquip est deserunt commodo eu eiusmod cillum.", "Nisi laboris velit Lorem irure." ], "results": [ { "sub_criteria_id": 0, "sub_criteria_score": 8.1561 } ] } ], "results_selective": [ { "type": "selective", "selective_criteria_id": 0, "selective_criteria": "Aute veniam quis adipisicing sint est amet aliquip elit.", "results": [ { "option_id": 0, "option_score": 3 }, { "option_id": 1, "option_score": 4 }, { "option_id": 2, "option_score": 5 }, { "option_id": 3, "option_score": 2 } ] }, { "type": "selective", "selective_criteria_id": 1, "selective_criteria": "Ipsum culpa dolore ad culpa amet aute ad.", "results": [ { "option_id": 0, "option_score": 3 } ] } ]}
-
미해결따라하며 배우는 리액트 A-Z
tailwindcss 적용이 안 됩니다
따라 치면서 실습하는데 적용이 안 되길래 삽질 하다가혹시나 싶어서 강의 자료를 다운 받아 npm run start 해 보았는데요그것도 이렇게 적용이 안 되게 보이네요...뭐가 문제일까요? ㅜ.ㅜ
-
미해결[리뉴얼] 타입스크립트 올인원 : Part1. 기본 문법편
Exclude 만들기에서 extends 구문 질문
type Exclude<T,U> = T extends U ? never : TExclude<Animal, 'Human'>그런데 T가 U보다 넓은거니까U extends T가 맞지 않나요? ㅠ PS. 아.. 혹시 하나하나 읽히는거면 equal로 해석해도 되는건가요?
-
해결됨Vue.js + TypeScript 완벽 가이드
2022-10-06 두번째 프로젝트 Repo 권한 요청 드립니다.
seokho.j0308@gmail.com입니다.
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 레딧 사이트 만들기(NextJS)(Pages Router)
cookie-parser Invalid or unexpected token error
영상에 따라서 단순하게 cookie-parser 설치하고 import cookie-parser 한다음에 app.use(cookieParser()) 진행하면 상단에 이미지처럼 에러가 발생하더라구요. cookie-parser을 제거하면 cookie가 정상적으로 저장되는 것을 볼 수 있었습니다. 어떤 부분을 놓친 것일까요server.tsimport express from "express"; import morgan from "morgan"; import { AppDataSource } from "./data-source" import authRoutes from "./routes/auth"; import subRoutes from "./routes/subs"; import cors from 'cors'; import dotenv from 'dotenv'; import cookieParser from "cookie-parser"; const app = express(); dotenv.config(); app.use(cors({ origin: process.env.ORIGIN, credentials: true })) app.use(express.json()); app.use(morgan('dev')); app.use(cookieParser()) app.get("/", (_, res) => res.send("running")); app.use('/api/auth', authRoutes); app.use("/api/subs", subRoutes); const PORT = process.env.PORT; console.log('PORT', PORT) app.listen(PORT, async () => { console.log(`server running at http://localhost:${PORT}`); AppDataSource.initialize().then(async () => { console.log("data initialize...") }).catch(error => console.log(error)) })
-
미해결따라하며 배우는 리액트 A-Z
useMemo hook 질문
강의 내용 중 useMemo 부분의 실습이 없어서 질문드립니다. Component.js로 컴포넌트를 작성하고App.js에서 컴포넌트를 호출해봤는데요. App.js..<div>{<Component a={1} b={5} />}</div> ... Component.js...useMemo(() => compute(a,b),[a,b]); ...이렇게 작성했을 때 useMemo가 제대로 작동하고 있는지 확인하고 싶은데요. useEffect는 console.log로 확인이 됐는데 useMemo는 어떻게 확인을 할 수 있을까요?(useEffect랑 useMemo는 방식이 달라서 useEffect에 로그를 찍어봤자 useMemo를 확인할 수 없었어요...)