간단하게 데이터처리와, 데이터 출력을 분리하는거다.
Container : API Request, Exception Error, setState... ETC...
Presenter : only Props, UI, no logic
import React from 'react'
import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useForm } from 'react-hook-form';
import { RootState } from 'store';
import { logIn } from 'store/users/actions';
import LogInPresenter from './presenter';
import StatusModal from 'components/StatusModal';
import { LogInInfo } from 'store/users/types';
const LogInContainer = () => {
const dispatch = useDispatch();
const [isOpenModal, setIsOpenModal] = useState(false);
const [errorMessage, setErrorMessage] = useState('');
const userReducer = useSelector((state: RootState) => state.userReducer);
const { register, errors, handleSubmit } = useForm<LogInInfo>();
const handleLogin = (data) => {
dispatch(logIn.request(data));
};
useEffect(() => {
if (userReducer.errorMessage !== '') {
setErrorMessage(userReducer.errorMessage);
setIsOpenModal(true);
}
}, [userReducer.errorMessage]);
return (
<LogInPresenter
onSubmit={handleLogin}
handleSubmit={handleSubmit}
register={register}
errors={errors}
/>
);
};
export default LogInContainer;
Container에는 데이터처리를 위한 state관리나 api request등만 정의되 있고, 화면 출력을 위해 Presenter를 상속받아 필요한 Props를 넘겨준다.
import React from 'react';
import TextInput from 'components/TextInput';
import { DeepMap, FieldError } from 'react-hook-form';
import styled from 'styled-components';
type inputProps = {
email: string;
password: string;
};
type RefReturn =
| string
| ((instance: HTMLInputElement | null) => void)
| React.RefObject<HTMLInputElement>
| null
| undefined;
type Props = {
onSubmit: (event: React.FormEvent<HTMLFormElement>) => void;
handleSubmit: Function;
register: ({ required }: { required?: boolean }) => RefReturn;
errors: DeepMap<inputProps, FieldError>;
};
const LogInPresenter = ({
onSubmit,
handleSubmit,
register,
errors,
### }: Props) => {
return (
<LoginForm onSubmit={handleSubmit(onSubmit)} className="input-group">
<TextInput type="email" label="email" register={register} required />
{errors.email && <ErrorMessage>⚠이메일을 입력해주세요</ErrorMessage>}
<TextInput
type="password"
label="password"
register={register}
required
/>
{errors.password && <ErrorMessage>⚠비밀번호를 입력해주세요</ErrorMessage>}
<LoginButton type="submit" className="login" value="Login" />
</LoginForm>
);
};
Presenter는 Container가 넘겨준 Props를 가지고 데이터를 출력하고, 화면을 구성하게 된다.
import LogInContainer from './container';
export default LogInContainer;
그 덕분에 index는 굉장히 간결해졌다. Container를 상속해서 다른 컴포넌트에서 사용할 수 있도록 export해주면 끝!
Container, Presenter 패턴도 적용하니 개발을 할 때 가독성이 좋아지고, 관리가 굉장히 편해졌다. 물론 Typescript를 사용하고 있기 때문에, Type지정하는게 처음엔 굉장히 익숙치 않았다. 하지만 적응되니 내가 볼때도 편하고 나중에 이게 뭐였지? 하며 고민하는 일도 줄었다. 다음엔 사용한 React Hook에 대해 정리하고자 한다.