강의

멘토링

커뮤니티

Cộng đồng Hỏi & Đáp của Inflearn

Hình ảnh hồ sơ của yjym33
yjym33

câu hỏi đã được viết

Mã hóa Slack Clone [Trò chuyện trực tiếp với React]

Thiết kế địa chỉ Router (Tham số Route)

채널 생성시 개발자도구에서

Viết

·

740

0

안녕하세요 채널 생성시  채널생성이 되지 않고 개발자도구 network란에 "존재하지 않는 워크스페이스 입니다" 라고 뜹니다. 타이핑도 모두 동일하고 어느부분이 잘못됬는지 잘 모르겠습니다.

 

typescriptbabelSocket.io웹팩react클론코딩

Câu trả lời 11

0

yjym33님의 프로필 이미지
yjym33
Người đặt câu hỏi

그리고 브라우저 주소창은 다음과 같이 나타납니다.

http://localhost:3090/workspace/sleact/channel/일반

0

yjym33님의 프로필 이미지
yjym33
Người đặt câu hỏi

layout/workspace/index.tsx  전체 코드입니다.

import {
  Channels,
  Header,
  ProfileImg,
  RightMenu,
  Workspaces,
  WorkspaceWrapper,
  WorkspaceName,
  Chats,
  MenuScroll,
  ProfileModal,
  LogOutButton,
  WorkspaceButton,
  AddButton,
  WorkspaceModal
} from '@layouts/Workspace/styles';
import fetcher from '@utils/fetcher';
import axios from 'axios';
import React,{ VFC, useCallback, useState }  from 'react';
import { Redirect, useParams } from 'react-router';
import { Link, Route, Switch } from 'react-router-dom';
import useSWR from 'swr';
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 { toast } from 'react-toastify';
import CreateChannelModal from '@components/CreateChannelModal';
import InviteWorkspaceModal from '@components/InviteWorkspaceModal';
import InviteChannelModal from '@components/InviteChannelModal';

const Channel = loadable(() => import('@pages/Channel'));
const DirectMessage = loadable(() => import('@pages/Channel'));


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, setNewWorkspace] = useInput('');
    const [newUrl, onChangeNewUrl, setNewUrl] = useInput('');

    const { workspace } = useParams<{workspace: string}>();
    const { data: userData, error, revalidate } = 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 onLogout = useCallback(() => {
      axios.post('http://localhost:3095/api/users/logout', null, {
          withCredentials: true,
      })
       .then(() => {
        revalidate();
       })
    }, []);

    const onCloseUserProfile = useCallback((e) => {
      e.stopPropagation();
      setShowUserMenu(false);
    }, []);

    const onClickUserProfile = useCallback(() => { // 토글함수
      console.trace('click');
      setShowUserMenu((prev) => !prev);
    }, []);

    const onClickCreateWorkspace = useCallback(() => {
      setShowCreateWorkspaceModal(true);
    }, []);

    const onCreateWorkspace = useCallback((e) => {
      e.preventDefault();
      if(!newWorkspace || !newWorkspace.trim()) return;
      if(!newUrl || !newUrl.trim()) return;
      if(!newWorkspace) return;
      axios
      .post('http://localhost:3095/api/workspaces', {
        workspace: newWorkspace,
        url: newUrl,
      },   {
        withCredentials: true,
      })
      .then(() => {
        revalidate();
        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);
      setShowInviteWorkspaceModal(false);
      setShowInviteChannelModal(false);
    }, []);

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

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

    const onClickInviteWorkspace = useCallback(() => {

    }, []);

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

    return(
        <div>
          <Header>
           <RightMenu>
             <span onClick={onClickUserProfile}>
               <ProfileImg src={gravatar.url(userData.nickname, { 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>
                {channelData?.map( (v) => (
                 <div>{v.name}</div>
                ))}
              </MenuScroll>
            </Channels>
            <Chats>
              <Switch> {/* workspace 안에서 Switch Route 사용 (중첩 라우팅)  */}
              <Route path="/workspace/:workspace/channel/:channel" component={Channel} />
              <Route path="/workspace/:workspace/dm/:id" component={DirectMessage} />
              </Switch>
            </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;
 

 

 

0

yjym33님의 프로필 이미지
yjym33
Người đặt câu hỏi

그러면 어느 부분을 보여드려야 되나요? 

 

app의 index.tsx 코드는 다음과 같습니다.

import React from 'react';
import loadable from '@loadable/component';
import { Switch, Route, Redirect } from 'react-router-dom';

// 코드 스플리팅
const LogIn = loadable(() => import('@pages/LogIn'));
const SignUp = loadable(() => import('@pages/SignUp'));
const Workspace = loadable(() => import('@layouts/Workspace')) // workspace만 등록

const App = () => {
  return (
    <Switch>
      <Redirect exact path="/" to="/login" />
      <Route path="/login" component={LogIn} />
      <Route path="/signup" component={SignUp} />
      <Route path="/workspace" component={Workspace} />
    </Switch>
  );
};

export default App;
zerocho님의 프로필 이미지
zerocho
Người chia sẻ kiến thức

layouts/Workspace.tsx 보여주세요.

zerocho님의 프로필 이미지
zerocho
Người chia sẻ kiến thức

그리고 브라우저 주소창도 확인해보세요.

zerocho님의 프로필 이미지
zerocho
Người chia sẻ kiến thức

https://github.com/ZeroCho/sleact/blob/master/front/layouts/App/index.tsx#L16

여기가 다르네요.

이 부분이 없어서 useParams의 workspace가 undefined였습니다.

yjym33님의 프로필 이미지
yjym33
Người đặt câu hỏi

제로초님 번거롭게 해드려서 죄송하지만 해당부분을 수정해도 계속해서 같은 오류가 발생합니다.

yjym33님의 프로필 이미지
yjym33
Người đặt câu hỏi

Warning: Each child in a list should have a unique "key" prop.

 

Check the render method of `Workspace`. See https://reactjs.org/link/warning-keys for more information.

    at div

    at Workspace (http://localhost:3090/dist/layouts_Workspace_index_tsx.js:797:90)

    at InnerLoadable (http://localhost:3090/dist/app.js:177:34)

    at LoadableWithChunkExtractor

    at Loadable

    at Route (http://localhost:3090/dist/app.js:54800:29)

    at Switch (http://localhost:3090/dist/app.js:55002:29)

    at App

    at Router (http://localhost:3090/dist/app.js:54431:30)

    at BrowserRouter (http://localhost:3090/dist/app.js:54048:35)

zerocho님의 프로필 이미지
zerocho
Người chia sẻ kiến thức

계속 주소에 undefined가 있는 것인가요? useParams에서 나온 workspace를 console.log 해보세요. 그리고 workspace를 사용하는 모든 useCallback에 [workspace]가 되어있는지도요.

yjym33님의 프로필 이미지
yjym33
Người đặt câu hỏi

app.js:1667 GET http://localhost3095/api/workspaces/sleact/channels net::ERR_NAME_NOT_RESOLVED

zerocho님의 프로필 이미지
zerocho
Người chia sẻ kiến thức

localhost3095 오타입니다. localhost:3095입니다.

yjym33님의 프로필 이미지
yjym33
Người đặt câu hỏi

아.. localhost3095 오류는 제로초님이 말씀해주셔서 수정했습니다 ㅠㅠ 감사합니다 

yjym33님의 프로필 이미지
yjym33
Người đặt câu hỏi

react_devtools_backend.js:2526 Warning: Each child in a list should have a unique "key" prop.

 

Check the render method of `Workspace`. See https://reactjs.org/link/warning-keys for more information.

    at div

    at Workspace (http://localhost:3090/dist/layouts_Workspace_index_tsx.js:797:90)

    at InnerLoadable (http://localhost:3090/dist/app.js:177:34)

    at LoadableWithChunkExtractor

    at Loadable

    at Route (http://localhost:3090/dist/app.js:54800:29)

    at Switch (http://localhost:3090/dist/app.js:55002:29)

    at App

    at Router (http://localhost:3090/dist/app.js:54431:30)

    at BrowserRouter (http://localhost:3090/dist/app.js:54048:35)

yjym33님의 프로필 이미지
yjym33
Người đặt câu hỏi

위 오류는 계속 발생하는것 같습니다.. ㅠㅠ

zerocho님의 프로필 이미지
zerocho
Người chia sẻ kiến thức

이건 오류가 아닙니다. 그냥 경고일 뿐입니다.

yjym33님의 프로필 이미지
yjym33
Người đặt câu hỏi

아 그렇군요.. 그런데 채널 생성은 계속 안되는거 같아요.. 

 

  1. Error: Request failed with status code 404 at createError (http://localhost:3090/dist/app.js:2132:15) at settle (http://localhost:3090/dist/app.js:2406:12) at XMLHttpRequest.onloadend (http://localhost:3090/dist/app.js:1534:7)
    1. isAxiosErrortrue
    2. response:
      1. data"존재하지 않는 워크스페이스입니다."
      2. status404
      3. statusText"Not Found"
    3. message"Request failed with status code 404"
    4. stack"Error: Request failed with status code 404\n at createError (http://localhost:3090/dist/app.js:2132:15)\n at settle (http://localhost:3090/dist/app.js:2406:12)\n at XMLHttpRequest.onloadend (http://localhost:3090/dist/app.js:1534:7)"

 

채널 생성 할때마다 이 오류메세지를 계속 뱉는거 같습니다,..

늦은시간까지 귀찮게 해드려서 죄송합니다.

zerocho님의 프로필 이미지
zerocho
Người chia sẻ kiến thức

'http://localhost:3095/api/workspaces/undefined/channels

저기 언디파인드가 들어가는 것은 onCreateChannel에 [workspace] 이런 게 없어서 그럴 수 있습니다.

0

yjym33님의 프로필 이미지
yjym33
Người đặt câu hỏi

백엔드 쪽이 문제이면 node_modules를 지웠다가 처음 세팅하신 순서대로 npm i 부터 db:seed:all까지 다시 한번 세팅을 해보는게 나을까요?

zerocho님의 프로필 이미지
zerocho
Người chia sẻ kiến thức

프론트엔드가 문제입니다. <Route path="..." 여기 코드에서부터 에러가 있을 수 있습니다.

일단 저기가 왜 undefined가 되는지부터 파악해야 합니다. App.tsx 코드 체크해보세요.

zerocho님의 프로필 이미지
zerocho
Người chia sẻ kiến thức

지금보니까 주소가

localhost3095

오타네요.

0

yjym33님의 프로필 이미지
yjym33
Người đặt câu hỏi

그래도 지속적으로 오류가 발생하네요.. ㅠㅠ 

바뀌고 나서는 다른 오류가 생겼습니다..

0

yjym33님의 프로필 이미지
yjym33
Người đặt câu hỏi

아 이부분을 말씀하신것 같아서 이부분도 수정했습니다.

 

   const onCreateChannel = useCallback(
      (e) => {
        e.preventDefault();
        axios
          .post(
            `http://localhost3095/api/workspaces/${workspace}/channels`,
            {
              name: newChannel,
            },
            {
              withCredentials: true,
            },
          )
          .then((response) => {
            setShowCreateChannelModal(false);
            revalidateChannel();
            setNewChannel('');
          })
          .catch((error) => {
            console.dir(error);
            toast.error(error.response?.data, { position: 'bottom-center' });
          });
      },
      [workspace, newChannel],
    );
 

0

yjym33님의 프로필 이미지
yjym33
Người đặt câu hỏi

백엔드 과정에서 해당 명렁어를 수행했습니다.. 

기존에도 잘 나왔었는데 이 부분 진행하면서 오류가 계속 뜨는거 같아요..

그리고 

"onCreateChannel의 deps 배열에 [workspace, newChannel]이어야 하는데 workspace가 빠져있네요."

라고 말씀해주셨는데 코드를 봐도 어느부분이 빠진지를 모르겠습니다..  제로초님 깃허브에서 똑같이 가져와서 해당부분 비교했는데 다른부분이 없는것 같아서요..

zerocho님의 프로필 이미지
zerocho
Người chia sẻ kiến thức

밑에 말씀드린대로 배열에 추가하세요.

0

zerocho님의 프로필 이미지
zerocho
Người chia sẻ kiến thức

백엔드 생성 과정에서 sequelize seed:all 관련 명령어 수행하셨나요?

일단 url이 /api/workspaces/undefined/channels 입니다. 저 부분이 undefined네요.

onCreateChannel의 deps 배열에 [workspace, newChannel]이어야 하는데 workspace가 빠져있네요.

0

yjym33님의 프로필 이미지
yjym33
Người đặt câu hỏi

그리고 콘솔창에서 지속적으로 404 에러가 발생합니다..

0

yjym33님의 프로필 이미지
yjym33
Người đặt câu hỏi

CreateChannelModal 부분쪽 코드도 올립니다.

어느 부분이 문제인지를 잘 모르겠습니다.

 

import Modal from "@components/Modal";
import useInput from "@hooks/useInput"; // 커스텀 Hooks
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, } 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, error, revalidate } = useSWR<IUser | false>(
        'http://localhost:3095/api/users',
        fetcher,
        {
          dedupingInterval: 2000, // 2초
        }
      );
     
      const { data: channelData, revalidate: revalidateChannel } = useSWR<IChannel[]>(
        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);
      revalidateChannel();
      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;

0

yjym33님의 프로필 이미지
yjym33
Người đặt câu hỏi

console 란에서도 아래와 같은 오류로 에러메세지를 뱉습니다.

app.js:1667 POST http://localhost:3095/api/workspaces/undefined/channels 404 (Not Found)

  1. Error: Request failed with status code 404 at createError (http://localhost:3090/dist/app.js:2132:15) at settle (http://localhost:3090/dist/app.js:2406:12) at XMLHttpRequest.onloadend (http://localhost:3090/dist/app.js:1534:7)
    1. isAxiosErrortrue
    2. response:
      1. data"존재하지 않는 워크스페이스입니다."
      2. status404
      3. statusText"Not Found"
    3. message"Request failed with status code 404"
    4. stack"Error: Request failed with status code 404\n at createError (http://localhost:3090/dist/app.js:2132:15)\n at settle (http://localhost:3090/dist/app.js:2406:12)\n at XMLHttpRequest.onloadend (http://localhost:3090/dist/app.js:1534:7)"
Hình ảnh hồ sơ của yjym33
yjym33

câu hỏi đã được viết

Đặt câu hỏi