리액트 슬랙 클론코딩 #2

Hyeonu_J·2022년 1월 21일
0
post-custom-banner

배운것 :

typings/db.ts

// 백엔드에서 보내는 데이터에 대한 타입
export interface IUser {
  id: number;
  nickname: string;
  email: string;
  Workspaces: IWorkspace[];
}
...
(생략)
...
export interface IWorkspace {
  id: number;
  name: string;
  url: string;
  OwnerId: number;
}

Workspace/index.tsx

import {IUser} from '@typings/db';
...(생략)...
// useSWR 뒤에 붙이는건 위에서 본 데이터의 타입이다. 로그인에 안 되어 있으면 false 를 전달한다.
const {data:userData,error,mutate} = useSWR<IUser | false>('http://localhost:3095/api/users', fetcher)

Typescript를 이용해서 Props를 보낼 때 익명함수 e도 아래처럼 타입을 표시해두자!

Menu/index.tsx

interface Props {
    show:boolean;
// ★ onCloseModal:() => void; 로 하면 안됨 !! ★ //
    onCloseModal:(e:any) => void;
    style:CSSProperties;
    closeButton?:boolean;
}

const Menu:FC<Props> = ({children,style,show,onCloseModal,closeButton}) => {
...(생략)...

Workspace/index.tsx

...(생략)...
    const onCloseUserProfile = useCallback((e)=>{
        e.stopPropagation();
        setShowUserMenu((prev)=>!prev);
    },[])
...(생략)...
                <RightMenu>
                    <span onClick={onCloseUserProfile}>
                        <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>

Workspace/index.tsx

...(생략)...
    const onCreateWorkspace = useCallback((e)=>{
        e.preventDefault()
        // 필수값들 다 들어있나 검사
        if(!newWorkspace || !newWorkspace.trim()) return;
        if(!newUrl || !newUrl.trim()) return;
        // if(!newWorkspace) return;
        // 위에 주석처리한 것처럼 단순히 검사하는 경우가 많은데,
        // 이 경우 띄어쓰기가 하나도 없을 때도 검사가 통과 된다.
        // 띄어쓰기까지 막으려면 위에처럼 trim() 을 넣어주자.
        axios.post('api/workspaces',{
            workspace:newWorkspace,
            url:newUrl,
        })
        .then(()=>{
            mutate();
            // 아래는 데이터 전송 했으면 초기값으로 설정
            setShowCreateWorkspaceModal(false);
            setNewWorkspace('')
            setNewUrl('');
        },{
            //이 값을 true 로 해줘야 내가 로그인 된 상태인 걸 쿠키로 알 수 있다!
            withCredentials:true,
        })
        .catch((error)=>{ // 에러난 경우 콘솔로그 찍기
            console.dir(error);
            // 아래 코드는 사용자에게 오류날 경우 왜 오류났는지 표시해주는 코드이다.
            // npm i react-toastify 한 후에
            // import {toast} from 'react-toastify' 로 불러온다.
            toast.error(error.response?.data,{position:'bottom-center'});
        });
    },[newWorkspace,newUrl]);
...(생략)...

기타 메모

<input> 이 있으면 따로 별도의 컴포넌트로 빼주자. 안그러면 리렌더링이 빈번하게 일어나게 된다. 큰 문제는 아닌데 성능 최적화를 위해 해주자.

form 을 onSubmit 할 때 e.preventDefault() 를 항상 써주자.

profile
흔한 컴공러 / 3학년
post-custom-banner

0개의 댓글