백 엔드 서버를 가동하고 로그인을 하면 이러한 창이 뜹니다.
이 상태에서 새로고침을 하면 정상적으로 워크스페이스를 제대로 가져오는데 혹시 가져오기 직전에(userData가 undefined) 화면이 렌더링 돼서 저러한 에러가 뜨는걸까요?
아무리 해결을 해보려 해도 되지 않아 이렇게 질문 남깁니다.
import React, { VFC, useCallback, useState } from 'react';
import useSWR from 'swr';
import fetcher from '@utils/fetcher';
import axios from 'axios';
import { Redirect, Route } from 'react-router';
import {
Header,
RightMenu,
ProfileImg,
WorkspaceWrapper,
Workspaces,
Channels,
Chats,
WorkspaceName,
MenuScroll,
ProfileModal,
LogOutButton,
WorkspaceButton,
AddButton,
WorkspaceModal,
} from '@layouts/Workspace/styles';
import gravatar from 'gravatar';
import { toast } from 'react-toastify';
import { IUser } from '@typings/db';
import { Link, Switch } from 'react-router-dom';
import loadable from '@loadable/component';
const Channel = loadable(() => import('@pages/Channel'));
const DirectMessage = loadable(() => import('@pages/DirectMessage'));
import Menu from '@components/Menu';
import { Button, Input, Label } from '@pages/SignUp/styles';
import useInput from '@hooks/useInput';
import Modal from '@components/Modal';
import CreateChannelModal from '@components/CreateChannelModal';
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 {
data: userData,
revalidate,
mutate,
} = useSWR<IUser | false>('http://localhost:3095/api/users', fetcher, {
dedupingInterval: 2000,
});
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 }, // CORS
)
.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);
}, []);
const toggleWorkspaceModal = useCallback(() => {
setShowWorkspaceModal((prev) => !prev);
}, []);
const onClickAddChannel = useCallback(() => {
setShowCreateChannelModal(true);
}, []);
if (!userData) {
return <Redirect 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.email, { 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={onClickAddChannel}>채널 만들기</button>
<button onClick={onLogout}>로그아웃</button>
</WorkspaceModal>
</Menu>
</MenuScroll>
</Channels>
<Chats>
<Switch>
<Route path="/workspace/channel" component={Channel} />
<Route path="/workspace/dm" 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} />
</div>
);
};
export default Workspace;
항상 질 좋은 강의 잘 듣고 있습니다.