input 이 있는 컴포넌트는 따로 분리해주자!
(안그러면 다른 부분이 리렌더링 되서 최적화 할 때 불편하다)
Workspace/index.tsx
<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>
CreateChannelModal/index.tsx
return (
<Modal show={show} onCloseModal={onCloseModal}>
<form onSubmit={onCreateChannel}>
<Label id="channel-label">
<span>채널</span>
<Input id="channel" value={newChannel} onChange={onChangeNewChannel}/>
</Label>
<Button type="submit">생성하기</Button>
</form>
</Modal>
)
코드 스플리팅에 대한것
App.tsx
const App = () => {
return (
<Switch>
<Redirect exact path="/" to="/login"/>
<Route path="/login" component={LogIn}/>
<Route path="/signup" component={SignUp}/>
{/* '/workspace/channel', 'workspace/dm' 이 아니라
아래처럼 주소칸 뒤에 클론을 붙이면 특수한 역할(와일드카드) 역할을 한다.*/}
<Route path="/workspace/:workspace" component={Workspace}/>
{/* 또한 예를 들어 여기에 workspace/channel 주소가 있으면 실행이 안 된다 */}
</Switch>
)
};
Workspace/index.tsx
...(생략)...
<Switch>
<Route path="/workspace/:workspace/channel/:channel" component={Channel}/>
<Route path="/workspace/:workspace/dm/:id" component={DirectMessage}/>
</Switch>
...(생략)...
CreateChannelModal/index.tsx
// useParams 훅으로 위에 써져있는 파라미터 뒤의 값들을 불러올 수 있다!
import { useParams } from 'react-router';
...(생략)...
const { workspace, channel } = useParams<{workspace:string;channel:string}>();
const onCreateChannel=useCallback(()=>{
axios.post(`/api/workspaces/${workspace}/channels`,{
name:newChannel,
},{
withCredentials:true //쿠키전달
})
},[newChannel]);
위에 gif처럼 채널을 만드는 모달에 적용된 코드이다.
보고 이해하지
import Modal from '@components/Modal'
import useInput from '@hooks/useInput';
import { Button, Input, Label } from '@pages/SignUp/styles';
import { IChannel, IUser } from '@typings/db';
import fetcher from '@utils/fetcher';
import axios from 'axios';
import React, { useCallback, VFC } from 'react';
import { useParams } from 'react-router';
import { toast } from 'react-toastify';
import useSWR from 'swr';
interface Props{
show:boolean;
onCloseModal:()=>void;
setShowCreateChannelModal:(flag:boolean) => void;
}
const CreateChannelModal:VFC<Props> = ({show,onCloseModal,setShowCreateChannelModal}) => {
const [newChannel,onChangeNewChannel,setNewChannel] = useInput('');
const { workspace, channel } = useParams<{workspace:string;channel:string}>();
const { data:userData, error,mutate} = useSWR<IUser|false>(
'http://localhost:3095/api/users',
fetcher,
{
dedupingInterval:2000,
}
);
const {data:channelData,mutate:mutateChannel} = useSWR<IChannel[]>(
userData ? `http://localhost:3095/api/workspaces/${workspace}/channels` : null,
fetcher,
)
const onCreateChannel=useCallback((e)=>{
e.preventDefault();
axios.post(`http://localhost:3095/api/workspaces/${workspace}/channels`,{
name:newChannel,
},{
withCredentials:true //쿠키전달
},)
.then(() => {
setShowCreateChannelModal(false);
mutateChannel()
setNewChannel('')
})
.catch((error)=>{
console.dir(error);
toast.error(error.response?.data, {position:'bottom-center'});
})
},[newChannel]);
return (
<Modal show={show} onCloseModal={onCloseModal}>
<form onSubmit={onCreateChannel}>
<Label id="channel-label">
<span>채널</span>
<Input id="channel" value={newChannel} onChange={onChangeNewChannel}/>
</Label>
<Button type="submit">생성하기</Button>
</form>
</Modal>
)
}
export default CreateChannelModal