inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

묻고 답해요

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

채널 생성시 404오류

미해결

Slack 클론 코딩[실시간 채팅 with React]

안녕하세요!!! 강좌 열심히 따라하면서 배우는 중, 해결점을 찾을수 없는 부분이 있어서 질문합니다. *우선 리액트 v6를 사용하여 route가 아래와 같이 되었다는 것을 참고해주세요. **SWR역시 revalidate가 작동이 안되어, mutate사용하였습니다. [이슈사항] 채널 리스트는 잘 받아오는 것 같습니다. 하지만, 채널생성시 404에러가 발생합니다. 서버는 "존재하지 않는 워크스페이스입니다."라는 응답을 줍니다. 의심되는 것은 버전6 라우팅설정에 문제가 있지 않을까 생각되는데... 검색해봐도 딱히 잘못된것을 못 발견해서 이렇게 질문남깁니다. //CreateChannelModal 코드 import Modal from '@components/Modal' ; import React , { CSSProperties , useCallback , VFC } from 'react' ; import { Button , Input , Label } from '@pages/SignUp/styles' ; import useInput from '@hooks/useinput' ; import axios from 'axios' ; import { useParams } from 'react-router' ; import { toast } from 'react-toastify' ; import useSWR from 'swr' ; import { IChannel , IUser } from '@typings/db' ; import fetcher from '@utils/fetcher' ; 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 , error , mutate } = useSWR <IUser | false >( 'http://localhost:3095/api/users' , fetcher ) ; const { data : channelData , mutate : mutateChannel } = useSWR <IChannel[]>( // 로그인하지 않은상태이면 호출안하고 , null 로 userData ? `http://localhost:3095/api/workspaces/ ${workspace} /channels` : null, fetcher , ) ; const onCreateChannel = useCallback ( (e) => { e. preventDefault () ; axios . post ( 'http://localhost:3095/api/workspaces/${workspace}/channels' , { name: newChannel , } , { withCredentials : true, } , ) . then (() => { setShowCreateChannelModal( false ) ; mutateChannel() ; setNewChannel ( '' ) ; }) . catch ((error) => { console . dir (error) ; toast . error (error. 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 ; // Workspace 코드 import React , { VFC , useCallback , useState } from 'react' ; import useSWR , { mutate } from 'swr' ; import fetcher from '@utils/fetcher' ; import axios from 'axios' ; import { Routes , Route , Navigate , Link } from 'react-router-dom' ; import { Header , LogOutButton , ProfileImg , ProfileModal , RightMenu , WorkspaceWrapper , Workspaces , Channels , Chats , WorkspaceName , MenuScroll , WorkspaceButton , AddButton , WorkspaceModal , } from '@layouts/Workspace/styles' ; import gravatar from 'gravatar' ; import loadable from '@loadable/component' ; import Menu from '@components/Menu' ; import { IChannel , IUser } from '@typings/db' ; import { Button , Input , Label } from '@pages/SignUp/styles' ; import useInput from '@hooks/useinput' ; import Modal from '@components/Modal' ; import CreateChannelModal from '@components/CreateChannelModal' ; import { toast } from 'react-toastify' ; import { useParams } from 'react-router' ; const Channel = loadable (() => import ( '@pages/Channel' )) ; const DirectMessage = loadable (() => import ( '@pages/DirectMessage' )) ; const Workspace : VFC = () => { const [showUserMenu , setShowUserMenu ] = useState ( false ) ; const [showCreateWorkspaceModal , setShowCreateWorkspaceModal ] = useState ( false ) ; const [showWorkspaceModal , setShowWorkspaceModal ] = useState ( false ) ; const [showCreateChannelModal , setShowCreateChannelModal ] = useState ( false ) ; const [newWorkspace , onChangeNewWorkspace , setNewWorkspace ] = useInput ( '' ) ; const [newUrl , onChangeNewUrl , setNewUrl ] = useInput ( '' ) ; const { workspace } = useParams <{ workspace : string }>() ; const { data : userData , error , mutate } = useSWR <IUser | false >( 'http://localhost:3095/api/users' , fetcher ) ; const { data : channelData } = useSWR <IChannel[]>( // 로그인하지 않은상태이면 호출안하고 , null 로 userData ? `http://localhost:3095/api/workspaces/ ${workspace} /channels` : null, fetcher , ) ; const onLogout = useCallback ((e) => { e. preventDefault () ; axios . post ( 'http://localhost:3095/api/users/logout' , null, { withCredentials : true, }) . then ((response) => { mutate( false, false ) ; }) ; } , []) ; const onCloseUserProfile = useCallback ((e) => { e. stopPropagation () ; setShowUserMenu ( false ) ; } , []) ; const onClickUserProfile = useCallback (() => { setShowUserMenu ((prev) => !prev) ; } , []) ; const onClickCreateWorkspace = useCallback (() => { setShowCreateWorkspaceModal ( true ) ; } , []) ; const onCreateWorkspace = useCallback ( (e) => { e. preventDefault () ; if (!newWorkspace || !newWorkspace. trim ()) return; if (!newUrl || !newUrl. trim ()) return; axios . post ( 'http://localhost:3095/api/workspaces' , { workspace: newWorkspace , url: newUrl , } , { withCredentials : true, } , ) . then ((response) => { mutate(response. data ) ; setShowCreateWorkspaceModal ( false ) ; setNewWorkspace ( '' ) ; setNewUrl ( '' ) ; }) . catch ((error) => { console . dir (error) ; toast . error (error. response ?. data , { position : 'bottom-center' }) ; }) ; } , [newWorkspace , newUrl] , ) ; const onCloseModal = useCallback (() => { setShowCreateWorkspaceModal ( false ) ; setShowCreateChannelModal ( false ) ; } , []) ; const toggleWorkspaceModal = useCallback (() => { setShowWorkspaceModal ((prev) => !prev) ; } , []) ; const onClickAddChannel = useCallback (() => { setShowCreateChannelModal ( true ) ; } , []) ; if (!userData) { return <Navigate replace to ="/login" /> ; } return ( <div> <Header> <RightMenu> <span onClick = {onClickUserProfile} > <ProfileImg src = {gravatar. url ( userData . email , { s : '28px' , d : 'retro' })} alt = { userData . email } /> {showUserMenu && ( <Menu style = {{ right : 0 , top : 38 }} show = {showUserMenu} onCloseModal = {onCloseUserProfile} > <ProfileModal> <img src = {gravatar. url ( userData . email , { s : '36px' , d : 'retro' })} alt = { userData . email } /> <div> <span id ="profile-name" > { userData . email } </span> <span id ="profile-active" > Active </span> </div> </ProfileModal> <LogOutButton onClick = {onLogout} > 로그아웃 </LogOutButton> </Menu> )} </span> </RightMenu> </Header> <WorkspaceWrapper> <Workspaces> { userData ?. Workspaces ?. map ((ws) => { return ( <Link key = {ws. id } to = { '/workspace/${123}/channel/ 일반 ' } > <WorkspaceButton> {ws. name . slice ( 0 , 1 ). toUpperCase ()} </WorkspaceButton> </Link> ) ; })} <AddButton onClick = {onClickCreateWorkspace} > + </AddButton> </Workspaces> { /*<Workspaces>*/ } { /* {userData?.Workspaces.map((ws) => {*/ } { /* 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) => ( <div> {v. name } </div> ))} </MenuScroll> </Channels> <Chats> chats <Routes> <Route path ="/channel/:channel" element = { <Channel /> } /> <Route path ="/dm/:id" element = { <DirectMessage /> } /> </Routes> </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 ; //App코드입니다 import React from 'react' ; import loadable from '@loadable/component' ; import { Routes , Route , Navigate } from 'react-router-dom' ; const LogIn = loadable (() => import ( '@pages/LogIn' )) ; const SignUp = loadable (() => import ( '@pages/SignUp' )) ; const Workspace = loadable (() => import ( '@layouts/Workspace' )) ; const App = () => { return ( <Routes> <Route path ="/" element = { <LogIn /> } /> <Route path ="/login" element = { <LogIn /> } /> <Route path ="/signup" element = { <SignUp /> } /> <Route path ="/workspace/:workspace/*" element = { <Workspace /> } /> </Routes> ) ; } ; export default App ;

  • 채널생성오류
  • 클론코딩
  • 404오류
  • babel
  • 리액트v6
  • react
  • 웹팩
  • typescript
  • Socket.io
최인설 댓글 1 좋아요 0 조회수 279

인기 태그

인프런 TOP Writers

주간 인기글