인프런 커뮤니티 질문&답변

slack efub님의 프로필 이미지
slack efub

작성한 질문수

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

해당에러는 백엔드 문제인가요?

해결된 질문

작성

·

167

0

 

proxy서버를 켜도 404에러가 뜹니다.. 들어가면 존재하지 않는 워크페이스라고 합니다 조언을 얻을 수 있을까요,, 어느 파일에서 잘못된건지 모르겠어요

밑 코드는 workspace 코드입니다. 프록시서버가 안먹혀서 http는 수동으로 다 붙여놓은 상태입니다.


import ChannelList from '@components/ChannelList';
import DMList from '@components/DMList';
import InviteChannelModal from '@components/InviteChannelModal';
import InviteWorkspaceModal from '@components/InviteWorkspaceModal';
import Menu from '@components/Menu';
import Modal from '@components/Modal';
import useInput from '@hooks/useInput';

import {
  AddButton,
  Channels,
  Chats,
  Header,
  LogOutButton,
  MenuScroll,
  ProfileImg,
  ProfileModal,
  RightMenu,
  WorkspaceButton,
  WorkspaceModal,
  WorkspaceName,
  Workspaces,
  WorkspaceWrapper,
} from '@layouts/Workspace/styles';
import loadable from '@loadable/component';
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, { VFC, useCallback, useState, useEffect } from 'react';
import { Navigate, Routes, useParams } from 'react-router';
import { Link, Route } from 'react-router-dom';
import useSWR from 'swr';
import gravatar from 'gravatar';
import { toast } from 'react-toastify';
import CreateChannelModal from '@components/CreateChannelModal';

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 [showInviteWorkspaceModal, setShowInviteWorkspaceModal] = useState(false);
  const [showInviteChannelModal, setShowInviteChannelModal] = useState(false);
  const [showWorkspaceModal, setShowWorkspaceModal] = useState(false);
  const [showCreateChannelModal, setShowCreateChannelModal] = useState(false);
  const [newWorkspace, onChangeNewWorkspace, setNewWorkpsace] = 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, {
    dedupingInterval: 2000, // 2초
  });
  const { data: channelData } = useSWR<IChannel[]>(
    userData ? `http://localhost:3095/api/workspaces/${workspace}/channels` : null,
    fetcher,
  );
  const { data: memberData } = useSWR<IUser[]>(
    userData ? `http://localhost:3095/api/workspaces/${workspace}/members` : null,
    fetcher,
  );

  const onLogout = useCallback(() => {
    axios
      .post('http://localhost:3095/api/users/logout', null, {
        withCredentials: true,
      })
      .then(() => {
        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(() => {
          mutate();
          setShowCreateWorkspaceModal(false);
          setNewWorkpsace('');
          setNewUrl('');
        })
        .catch((error) => {
          console.dir(error);
          toast.error(error.response?.data, { position: 'bottom-center' });
        });
    },
    [newWorkspace, newUrl],
  );

  const onCloseModal = useCallback(() => {
    setShowCreateWorkspaceModal(false);
    setShowCreateChannelModal(false);
    setShowInviteWorkspaceModal(false);
    setShowInviteChannelModal(false);
  }, []);

  const toggleWorkspaceModal = useCallback(() => {
    setShowWorkspaceModal((prev) => !prev);
  }, []);

  const onClickAddChannel = useCallback(() => {
    setShowCreateChannelModal(true);
  }, []);

  const onClickInviteWorkspace = useCallback(() => {
    setShowInviteWorkspaceModal(true);
  }, []);

  if (!userData) {
    return <Navigate to="/login" />;
  }

  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 }} show={showUserMenu} onCloseModal={onCloseUserProfile}>
                <ProfileModal>
                  <img src={gravatar.url(userData.nickname, { s: '36px', 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) => {
            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>
            <ChannelList />
            <DMList />
          </MenuScroll>
        </Channels>
        <Chats>
          <Routes>
            <Route path="/workspace/channel/:channel" element={Channel} />
            <Route path="/workspace/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}
      />
      <InviteWorkspaceModal
        show={showInviteWorkspaceModal}
        onCloseModal={onCloseModal}
        setShowInviteWorkspaceModal={setShowInviteWorkspaceModal}
      />
      <InviteChannelModal
        show={showInviteChannelModal}
        onCloseModal={onCloseModal}
        setShowInviteChannelModal={setShowInviteChannelModal}
      />
    </div>
  );
};

export default Workspace;

답변 1

0

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

보시면 workspace가 undefined로 되어있습니다. 라우트 설정한 곳에서 문제가 있었을 겁니다.

slack efub님의 프로필 이미지
slack efub
질문자

const { data: channelData } = useSWR<IChannel[]>(
    userData ? `http://localhost:3095/api/workspaces/${workspace}/channels` : null,
    fetcher,
  );
  const { data: memberData } = useSWR<IUser[]>(
    userData ? `http://localhost:3095/api/workspaces/${workspace}/members` : null,
    fetcher,
  );

해당 코드를 강의와 똑같이 진행했는데,, 여기가 틀린게 아니라, app파일을 말씀하시는 걸까요?

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

<Route 있는 부분입니다~ 거기서 workspace를 useParams로 전달하거든요

slack efub님의 프로필 이미지
slack efub
질문자

image

제대로 처리해두었습니당,,ㅜㅜ

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

어떤 자료를 보신건가요??

https://www.inflearn.com/questions/417079

이런 식으로 하셔야합니다.

slack efub님의 프로필 이미지
slack efub
질문자

image넵,, 그런식으로 처리해 두었는데 아직도

image에러가 그대로 입니다..

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

아뇨 /workspace/:workspace쪽을 보세요.

slack efub님의 프로필 이미지
slack efub
질문자

image네 물론 그 부분도 고쳤습니다. 똑같습니다

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

지금 useSWR 부분도 또 수정하신 건가요? workspace 변수 자리에 :workspace가 들어가 있는 상황입니다. 브라우저의 주소창에 주소가 제대로 나와야합니다. workspace/sleact 이런 식으로요. 그래야 workspace 변수도 sleact가 됩니다.

slack efub님의 프로필 이미지
slack efub
질문자


const Workspace: VFC = () => {
  const [showUserMenu, setShowUserMenu] = useState(false);
  const [showCreateWorkspaceModal, setShowCreateWorkspaceModal] = useState(false);
  const [showInviteWorkspaceModal, setShowInviteWorkspaceModal] = useState(false);
  const [showInviteChannelModal, setShowInviteChannelModal] = useState(false);
  const [showWorkspaceModal, setShowWorkspaceModal] = useState(false);
  const [showCreateChannelModal, setShowCreateChannelModal] = useState(false);
  const [newWorkspace, onChangeNewWorkspace, setNewWorkpsace] = 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, {
    dedupingInterval: 2000, // 2초
  });
  const { data: channelData } = useSWR<IChannel[]>(
    userData ? `http://localhost:3095/api/workspaces/${workspace}/channels` : null,
    fetcher,
  );
  const { data: memberData } = useSWR<IUser[]>(
    userData ? `http://localhost:3095/api/workspaces/${workspace}/members` : null,
    fetcher,
  );

밑 파일은 login파일입니다. login을 통해서 워크스페이스를 확인하고 있는데, 밑과 같은 주소로 설정시 없는 라우터라고 떠서

image

아래와 같이 주소를 처리했었습니다.

image

app.index파일은

image다음과 같습니다. 어디서 틀린걸까요,,

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

뒤에 /*를 붙이셨으면 Navigate에서 원래대로 해도 없는 라우트라고 안 뜰 텐데요?? 그 부분은 바꿀 필요가 없습니다.

slack efub님의 프로필 이미지
slack efub
질문자

image해당 코드로 넣으면 아래처럼 주소와 404 에러가뜹니다..

 

image

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

아뇨 저렇게 넣지 마시고, Navigate에서는 강좌대로 넣으라는 말씀이었습니다. Route에서만 /* 붙이고요.

Route에서 /workspace/:workspace/* 했으니까

Navigate에서는 /workspace/sleact/channel/일반으로 가는거죠.

sleact가 :workspace에 대응되고, channel/일반이 /*에 대응되는 것이고요.

slack efub님의 프로필 이미지
slack efub
질문자

image해당 코드로 바꾸면

image이와 같은 에러가 떠서요,, 그래서 피해왔던 건데 이게 맞는건가요?

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

element={<Channel />} 하셔야하는데 element={Channel} 하신 것 같습니다.

slack efub님의 프로필 이미지
slack efub
질문자

강사님 감사합니다.. 덕분에 해결했습니다.. 오랜시간 동안 신경써주셔서 감사합니다 ㅜㅜ

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

한글자 한글자 잘 보셔야 합니다 ㅠㅠ 아 다르고 어 달라서요

slack efub님의 프로필 이미지
slack efub

작성한 질문수

질문하기