작성
·
302
0
안녕하세요.
Cannot read properties of undefined (reading 'map') 하여 질문을 드리고자합니다.
문제는 해결 했으나 타입스크립트가 미숙하여 이런 현상이 발생한거 같은데 왜 이런 문제가 발생했는지 잘 몰라서 질문 드립니다.
오류가 발생 된 flow는
login 시 /workspace/sleact/channel/일반 으로 접을 했을 경우
그림과 같은 에러가 발생하였습니다.
map 관련해서 초기 값이 안들어오는 부분의 에러인것을 확인하고 userData 옵셔널 체이닝을 에 해당 하는 값에 앞부분만 주었는데 에러가 발생한거 같습니다.
자세한 코드는 이렇습니다.
<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에도 옵셔널 체이닝을 걸어줘야 에러가 풀렸는데요.
제로초님의 코딩을 전부 클론하여 작성하였는데 왜 이런 문제가 발생했는지 이해를 못하고 있습니다.
혹여 typescript에서는 전부 옵셔널 체이닝을 적용해줘야하나요 ... ??
세부적인 코드는 아래 첨부드립니다.
아 그리고 userData는 정상적으로 다 받아옵니다.
import fetcher from '@utils/fetcher';
import axios from 'axios';
import { type } from 'os';
import React, { useCallback, ReactNode, useState } from 'react';
import { Redirect, Route, Switch, useParams } from 'react-router';
import useSWR from 'swr';
import {
Header,
RightMenu,
ProfileImg,
WorkspaceWrapper,
Workspaces,
Channels,
Chats,
WorkspaceName,
MenuScroll,
ProfileModal,
LogOutButton,
WorkspaceButton,
AddButton,
WorkspaceModal,
} from '@layouts/Workspace/styles';
import gravatar from 'gravatar';
import Channel from '@pages/Channel';
import DirectMessage from '@pages/DirectMessage';
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';
type Props = {
children?: ReactNode;
};
function Workspace({ children }: Props) {
const [showUserMenu, setShowUserMenu] = useState(false);
const [showCreateWorkspaceModal, setShowCreateWorkspaceModal] = useState(false);
const [showWorkSpaceModal, setShowWorkSpaceModal] = useState(false);
const [showCreateChannelModal, setShowCreateChannelModal] = useState(false);
const [newWorkSpace, onChangeNewSpace, setNewWorkSpace] = useInput('');
const [newUrl, onChangeNewUrl, setNewUrl] = useInput('');
const { workspace } = useParams<{ workspace: string }>();
const {
data: userData,
error,
revalidate,
mutate,
} = useSWR<IUser | false>('http://localhost:3095/api/users', fetcher);
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();
mutate(false, false);
});
}, []);
const onClickUserProfile = useCallback((e) => {
e.stopPropagation();
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(() => {
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>
{/* 우측 상단 프로필 active */}
<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={onClickUserProfile}>
<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>
<button onClick={onClickAddChannel}>채널만들기</button>
<button onClick={onLogout}>로그아웃</button>
</WorkspaceModal>
</Menu>
{channelData?.map((v) => (
<div>{v.name}</div>
))}
</MenuScroll>
</Channels>
<Chats>
<Switch>
<Route path="/workspace/:workspace/channel/:channel" component={Channel} />
<Route path="/workspace/:workspace/dm/:id" component={DirectMessage} />
</Switch>
</Chats>
</WorkspaceWrapper>
{/* 워크 스페이스 생성 모달 onClickCreateWorkspace */}
<Modal show={showCreateWorkspaceModal} onCloseModal={onCloseModal}>
<form onSubmit={onCreateWorkspace}>
<Label id="workspace-label">
<span>워크스페이스 이름</span>
<Input id="workspace" value={newWorkSpace} onChange={onChangeNewSpace}></Input>
</Label>
<Label id="workspace-label">
<span>워크스페이스 url</span>
<Input id="workspace" value={newUrl} onChange={onChangeNewUrl}></Input>
</Label>
<Button type="submit">생성하기</Button>
</form>
</Modal>
{/* 채널 만들기 모달 onClickAddChannel*/}
<CreateChannelModal
show={showCreateChannelModal}
onCloseModal={onCloseModal}
setShowCreateChannelModal={setShowCreateChannelModal}
/>
</div>
);
}
export default Workspace;
답변 1
0
userData가 있는게 확실하다면 userData.Workspaces가 없었던 것 같습니다.
근데 userData?.Workspaces?.map을 하셔서 최종적으로 문제가 해결된건가요?
워크스페이스 목록들이 전부 뜨나요? 그럼 크게 문제는 없습니다.
네네
userData?.Workspaces?.map 해서 해결 했고요.
Workspaces 목록은 array로 담겨 있습니다.
근데 이게 정확히 왜 그런지 모르겠네요.. 값이 있음에 불구하고