리액트와 타입스크립트를 이용하여 api 객체를 받아오는 방법에 대한 포스팅 순서이다.
1. React(45) 타입스크립트 - api 객체 받아오기 (상세페이지) 1
- api 로 서버에서 채팅방과 유저들의 정보를 받아와 회원 등급에 따른 채팅 리스트를 구현한다.
2. React(46) 타입스크립트 - api 객체 받아오기 (상세페이지) 2
- 구현한 채팅 리스트를 바탕으로 채팅 정보가 들어있는 상세 페이지를 구현해보았다.
React(46) 타입스크립트 - api 객체 받아오기 2 (상세페이지)
결과 화면
1. 통신메소드를 통해 컴포넌트 내에서 채팅방 리스트를 받아온다. [ 더보기 ] 버튼을 누르자.
2. [ 더보기 ] 를 누르면 customer 인 유저 정보와 그에 따른 1:1 채팅방 리스트로 연결된다. (상세페이지)
** 실제 코드는 리팩토링하여 구조 자체가 바뀌었으며, 초반에 작업한 코드를 모두가 볼 수 있도록 수정하여 참고용으로 포스팅합니다. 혹시 맞지 않는 부분이 있더라도 부족한 코드 양해부탁드립니다 :)
App.tsx
동적 라우트 기능을 이용하여 id 값에 따라 /user/:id 값도 달라지게 될거다. UserDetail 컴포넌트로 이동해보자
import { ReactElement } from 'react'
import { UserDetail } from 'pages'
import { UserList } from 'component/UserList'
const App = (): ReactElement => {
return (
<div className="app">
<Route exact path="/user/" component={UserList} />
<Route exact path="/user/:id" component={UserDetail} />
</div> // url에 ' /:id ' 를 넣으면 동적라우팅이 가능하다
)
}
export default App
pages/index.tsx
여기서 page 들을 전역적으로 관리하는 곳이다. 여길 거쳐서 UserDetail 로 가게 된다.
이렇게 해주는 이유는 ? 생각해보자. 추후에 뭐 하나 바뀌면 일일이 컴포넌트 찾아다니면서 수정하기 귀찮기 때문이다.
(모든건 귀차니즘에서 왔다고 해도 무방할 것이다.)
export { default as UserDetail } from 'pages/UserDetail';
pages/UserDetail.tsx
UserList 에서 [ 더보기 ] 버튼을 클릭해서 들어오는 UserDetail 페이지에서는
useEffect 가 처음 한번만 렌더링되고 getList() 를 통해 id 에 맞는 객체를 데려온다.
그리고 <UserItemDetail > 안에 prop 로 넣어 데이터를 내려보낸다.
import { ReactElement, useState, useEffect } from 'react';
import { useParams, useHistory } from 'react-router-dom';
import { User } from 'model/User';
import UserItemDetail from 'component/user/UserItemDetail';
import Header from 'components/Header';
import Footer from 'components/Footer';
import http from 'util/HttpConfig';
interface ParamID { // url 뒤에 나오는 param값의 타입을 정해주자
id: string | undefined // param으로 id 값을 사용할 것이므로, id 의 타입을 정하자
}
const UserDetail = (): ReactElement => {
const [userItem, setuserItem] = useState<User>() // userItem 은 api 객체를 넣을 변수이다
const history = useHistory() // '뒤로가기' 기능을 사용하기 위해 useHistory 를 선언
const id = useParams<ParamID>() // useParams으로 url/:id 값을 알수있다.
useEffect(() => {
GetUser() // 첫 렌더링시 GetUser()가 자동으로 렌더링해서 객체정보를 불러온다.
}, [])
async function GetUser() {
try { // 통신 성공시,
if (!id || id === '') { // id 값이 없을 때 예외 처리
alert('잘못된 주소를 입력하셨습니다.') // 경고창 처리해주고
history.push('/user') // user 페이지로 돌아가기
}
// 리스트로 객체정보 받아오기 이때 id 라는 객체 안에 id라는 키 값이 들어있다
const list = await http.get(`${api}/user/${id.id}`)
if (list.status !== 200) { // 통신 시 에러 처리
throw new Error(`Response status is "${list.status}"`);
}
if (list.data.resultData) { // list 로 데이터가 잘 저장되었으면
const resList: User[] = JSON.parse( // resList에 list객체를 json형식으로 변환하자
JSON.stringify(list.data.resultData)
)
setUserItem(resList) // resList 를 userList 안에 저 ~ 장
}
} catch (e) { // 통신 실패시 예외 처리
alert('정보를 가져오는데 실패하였습니다.') // 안내 경고창과 함께
console.error(e) // 콘솔에 에러 메시지 출력
history.push('/user') // user 페이지로 돌아가기
}
}
return (
<div className="user">
<Header>
// userItem 객체가 있는 경우에만 &&
// props 로 통신 메소드로 받아온 api 객체를 넘겨준다.
{userItem &&
<UserItemDetail user={userItem} key={userItem?.id} />
}
<Footer>
</div>
)
}
export default UserDetail
UserItemDetail.tsx
부모인 UserDetail 컴포넌트에서 받아온 prop를 interface 로 선언해줘야 한다.
useEffect 가 처음 한번만 렌더링되고 getChatList() 를 통해 id 에 맞는 객체를 데려온다.
특정 회원의 채팅리스트가 렌더링되며, 클릭시 selectChatRoom() 함수를 통해 채팅방으로 연결된다.
import { ReactElement, useState, useEffect, useMemo } from 'react';
import { useHistory } from 'react-router';
import { useSelector, useDispatch } from 'react-redux';
import { rootState } from 'redux';
import { setUser } from 'redux/User';
import { setChat } from 'redux/chat/Chat';
import { User } from 'model/User';
import { Chat, GetSimpleText } from 'model/Chat';
import { GetNick } from 'model/User';
import http from 'util/HttpConfig';
interface UserItemDetailProps {
user: User;
}
interface userInfo {
chatID: string;
customerID: string;
nick: string;
}
const UserItemDetail = (props: UserItemDetailProps): ReactElement => {
const [chatList, setChatList] = useState<ChatInfo[]>([])
const uid = useSelector((state: rootState) => state.user.uid);
const history = useHistory()
const dispatch = useDispatch()
useEffect(() => {
getChatList(props.user); // props의 user 객체를 매개변수로 넣어 함수를 실행한다.
}, []); // 최초렌더링 시에만 실행
// 가공한 채팅 객체 리스트를 가져오는 메소드
async function getChatList(user: User) { // 유저정보를 매개변수로 받는다
const chats: ChatInfo[] = [] // 채팅리스트 배열을 넣을 변수이다
if (!user.info || user.info.length === 0) { // user.info 값이 없다면
chats.push({ // chats 객체에 아래 데이터를 추가하자
chatID: user.chatID, // 매개변수로 받은 객체의 정보들을 하나씩 넣는다
customerID: user.uid,
nick: GetNick(user.uid),
})
} else { // user.info 값이 있다면
for (let i = 0; i < user.info.length; i++) { // 원소를 하나씩 검사한다
const info = user.info[i] // info를 user.info의 원소로 명명하자
if (user.uid !== uid && info.customerID !== uid) { // uid 가 참가자들거랑 다르다면
continue; // 컨티뉴! 걍 스킵!
}
let dup = false; // 채팅방 중복 생성 여부를 검사할 거다
for (let j = 0; j < chats.length; j++) { // chats 배열도 함께 검사한다.(2중반복문)
if (info.chatID === chats[j].chatID) { // info 와 chat 안의 chatID가 둘다 같다면
dup = true; // 중복이 true (맞으니)
break; // 그냥 빠져나오자
}
}
if (!dup) { // 만약 중복이 여전히 false (아니라면)
chats.push({ // chats 배열에 info의 데이터를 push 한다
chatID: info.chatID,
customerID: user.uid,
nick: getNick(user.uid),
})
}
}
}
setChatList(chats); // 그렇게 나온 chats 배열은 set 함수를 거쳐 chatList 가 된다.
return;
}
// 채팅 리스트 클릭하면 해당 채팅방으로 이동하는 함수
async function selectChat(user: User, cid: string) {
try { // 통신성공시
const res = await http.get( // res 에 chatID 에 해당하는 객체를 받아 저장한다.
`${api}/chat?chatID=${chatID}`
);
if (list.status !== 200) { // 통신 시 에러 처리
throw new Error(`Response status is "${list.status}"`);
}
const chat: Chat = JSON.parse( // chat은 가공된 res 객체가 들어갈 변수다
JSON.stringify(res.data.resultData[0]) // res객체를 json형식으로 변환하여 넣어놨다
)
dispatch(setUser(user)); // dispatch 로 리덕스에 접근해서 user 값으로 저장
dispatch(setChat(chat)); // 마찬가지로 리덕스의 chat 값으로 저장
history.push('/user/chat'); // 다 마쳤으면 /user/chat 으로 라우팅해준다.
} catch (e) { // 통신 실패시 예외 처리
alert('정보를 가져오지 못했습니다.') // 안내 경고창과 함께
console.error(e) // 콘솔에 에러 메시지 출력
history.push('/user') // user 페이지로 돌아가기
}
}
return (
<div className="chat-info">
{chatList.map((chat, index) => ( // chatList 배열을 map() 함수로 사용하자
<div
className="chat-detail"
key={chat.chatID} // 가장 최상단의 태그에 key 값을 넣는다
onClick={() => // onClick 시 해당 채팅방에 입장하는 함수를 실행
selectChat(props.user, chat.chatID)
}
>
<div>{chat.chatID}</div>
<div>{chat.customerID}</div>
<div>{chat.nick}</div>
</div>
))}
</div>
);
};
export default DealItemDetail;
'React' 카테고리의 다른 글
React(48) 타입스크립트 - 토글 메뉴에 animation 효과주기 (3) | 2021.09.14 |
---|---|
React(47) div영역에 mouseover 시 버튼 보이기 (0) | 2021.09.12 |
React(45) 타입스크립트 - api 객체 받아오기 1 (상세페이지) (0) | 2021.09.10 |
React(44) 리액트 훅 - useMemo 란? (0) | 2021.09.09 |
React(43) 리액트 훅 - useCallback 이란 (0) | 2021.09.07 |
댓글