본문 바로가기

웹 프레임워크/Javascript - React.js

[Javascript] React 디자인 패턴 design pattern presentational & container

728x90
  • 로직을 수행하는 컴포넌트, UI를 보여주는 컴포넌트를 분리
  • 앱의 기능과 UI구분이 쉬워짐
    같은 state를 다른 container에게 props를 내림으로써 공유
    로직수행, markup이 다른 컴포넌트에서 하기 때문에 유지보수가 쉽고, 재사용성이 뛰어남.
    markup 변경에 매우 유연함
    동일한 마크업, 컨테이너 레이아웃(header, footer 등)은 반복해서 작성하지 않고 구현 가능

presentational

  • 사용자가 직접 보고 조작하는 컴포넌트
  • state를 직접 조작하지 않고, container component가 내려준 props함수에 의해 state를 변경
    그에 따라 useState, useCallback 등 state관련 훅이 없어야함
  • 상태를 거의 가지지 않으며, 상태를 가진다면 데이터에 관한 것이 아닌 UI상태에 관한 것

container

  • 로직 관련 컴포넌트
  • markup, style을 사용하지 않아야함
  • 데이터와 데이터 조작에 관한 함수를 생성, present component에 제공
// LoginContainer.js
import React, { useState, useEffect } from 'react';
import LoginPresenter from './LoginPresenter';

const LoginContainer = (props) => {
  const [form, setForm] = useState({
      email: '',
    password: '',
  });

  const handleInputForm = (e) => setForm({ ...form, [e.target.name]: e.target.value });

  const handleSubmit = async (e) => {
    e.preventDefault();

    await fetch('localhost:3000/user/', {
      method: 'POST',
      headers: {
        Accept: 'application/json',
              'Content-Type': 'application/json',
        token: 'token',
      },
      body: JSON.stringify(form),
    }).then((res) => res.json())
        .then((res) => {
          if (res.status === 200) props.history.push('/');
        });
  };

  return (
    <LoginPresenter
      form={form}
      handleInputForm={handleInputForm}
      handleSubmit={handleSubmit}
    />
  );
};

export default LoginContainer;
// LoginPresenter.js
import React from 'react';

const LoginPresenter = (props) => (
    <div className="signin-wrap">
      <form method="POST" onSubmit={props.handleSubmit}>
        <div className="form_input_wrap mb-3">
        <input type="text" autoComplete="off" name="email" value={props.form.email} placeholder="아이디(이메일)" onChange={props.handleInputForm} />
      </div>
      <div className="form_input_wrap">
        <input type="password" autoComplete="off" name="password" value={props.form.password} placeholder="비밀번호" onChange={props.handleInputForm} />
      </div>
      <div className="form_btn_wrap mt-3 text-center">
        <button type="submit" className="btn btn-main mb-2">로그인</button>
        <p className="color_default text-left mt-0" style={{ fontSize: '15px' }}>
          <Link to="/users/find/email" className="color_default">아이디/ 비밀번호 찾기</Link>
          <Link to="/users/signup" className="color_blue float_right">회원가입</Link>
        </p>
      </div>
    </form>
  </div>
);

export default LoginPresenter;
728x90