Cannot read properties of undefined (reading 'map') 관련 질문드립니다.
329
작성한 질문수 14
안녕하세요.
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
106
1
초기 셋팅 back과 front만 남겨두고 다 지운 후 진행 방법
0
109
2
focus 시에만 화면 업데이트 되는 이유 + 해결방법
0
165
2
useEffect 개수 관리
0
122
2
라이브러리 서치 방법
0
118
2
함수 정의 패턴
0
80
1
npm run dev 에러
0
156
3
npx webpack 후 에러
0
187
2
'void' 형식 식의 truthiness를 테스트할 수 없습니다.ts(1345)
0
151
2
사용자 가입시 에러발생 (TypeError: Cannot read properties of null (reading 'addMembers')
1
192
2
초기세팅중 packge.json 에러떠요
0
162
2
CORS - Access-Control-Allow-Origin 누락 문제
0
439
3
로그인 페이지 무한 새로고침 현상
0
608
2
Module not found: Error: Can't resolve './App' 에러
0
970
1
배포 방법
0
306
2
npm run dev 시 빌드가 매우 느려졌습니다
0
1010
2
alias 경로 설정 오류
0
461
2
fetcher 함수의 data 값이 두번 찍히는 이유
0
282
1
제네릭 질문
0
225
2
ts-node 대신 tsx 사용여부
0
377
1
배포 관련 질문
0
249
1
[nginx + https] 서비스를 실행하면 niginx가 아닌 서비스 화면을 보여주게 하고 싶습니다.
0
395
2
[배포하기] webpack에 aws 퍼블릭 IPv4 주소 와 포트 주소를 작성하고 나서 빌드후 실행하면 오류가 발생합니다.
0
341
1
users 호출 시 쿠키가 담기지 않는 이슈 질문드립니다.
0
252
2





