@@ -0,0 +1,125 @@
+import React, { Component } from 'react';
+import { withRouter } from 'react-router-dom';
+import { API } from '../../../config';
+import './Login.scss';
+
+class LoginYeseul extends Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      inputId: '',
+      inputPw: '',
+      loginMode: true,
+    };
+  }
+
+  handleInput = e => {
+    const { name, value } = e.target;
+    this.setState({ [name]: value });
+  };
+
+  convertMode = () => {
+    this.setState({
+      loginMode: !this.state.loginMode,
+    });
+  };
+
+  signIn = e => {
+    const { inputId, inputPw } = this.state;
+    e.preventDefault();
+    fetch(API.SIGN_IN, {
+      method: 'POST',
+      body: JSON.stringify({
+        email: inputId,
+        password: inputPw,
+      }),
+    })
+      .then(users => users.json())
+      .then(users => {
+        if (users.MESSAGE === 'SUCCESS') {
+          this.setState({
+            inputId: '',
+            inputPw: '',
+          });
+          localStorage.setItem('token', users.ACCESS_TOKEN);
+          this.props.history.push('/main-yeseul');
+        } else if (users.MESSAGE === 'INVALID_USER') {
+          const wantToSignUp = window.confirm(
+            '잘못된 정보입니다. 회원가입하시겠습니까?'
+          );
+          wantToSignUp && this.convertMode();
+        }
+      });
+  };
+
+  signUp = e => {
+    const { inputId, inputPw } = this.state;
+    e.preventDefault();
+    fetch(API.SIGN_UP, {
+      method: 'POST',
+      body: JSON.stringify({
+        email: inputId,
+        password: inputPw,
+      }),
+    })
+      .then(users => users.json())
+      .then(users => {
+        if (users.MESSAGE === 'SUCCESS') {
+          this.setState({
+            inputId: '',
+            inputPw: '',
+          });
+          alert(`회원가입되었습니다!🎉 로그인해주세요`);
+          this.convertMode();
+        } else {
+          alert(users.MESSAGE);
+        }
+      });
+  };
+
+  render() {
+    const { inputId, inputPw, loginMode } = this.state;
+    const checkId = /^\w[\w\-.]*@\w+\.\w{2,}/;
+
+    return (
+      <main className="loginYeseul give-border">
+        <h1 className="logo">westagram</h1>
+        <form
+          className="login-form"
+          onSubmit={loginMode ? this.signIn : this.signUp}
+        >
+          <div className="login-form__input-box">
+            <input
+              type="text"
+              name="inputId"
+              placeholder="전화번호, 사용자 이름 또는 이메일"
+              value={inputId}
+              onChange={this.handleInput}
+            />
+            <input
+              type="password"
+              name="inputPw"
+              placeholder="비밀번호"
+              value={inputPw}
+              onChange={this.handleInput}
+            />
+          </div>
+          <button
+            type="submit"
+            disabled={!(checkId.test(inputId) && inputPw.length > 8)}
+          >
+            {loginMode ? '로그인' : '회원가입'}
+          </button>
+        </form>
+        <a
+          href="https://www.instagram.com/accounts/password/reset/"
+          className="find-pw"
+        >
+          비밀번호를 잊으셨나요?
+        </a>
+      </main>
+    );
+  }
+}
+
+export default withRouter(LoginYeseul);

리뷰: - API 부는 이후에 src/config.js 파일을 만들어 해당 파일에서 일괄적으로 관리합니다.
```js
// config.js
const IP = '10.58.6.252:8000';
export const SIGN_IN_API = `http://${IP}/user/signin`;


// Login.js
import { SIGN_IN_API } from '../../config.js';

...

fetch(SIGN_IN_API).then().then()

...
```

- 위와 같이 config.js 에서 일괄적으로 관리할경우, 백엔드 서버의 IP 가 변경되거나 혹은 엔드포인트가 변경되었을 때, config.js 에서만 한번 수정해주면 되기 때문에 유지보수가 편해집니다.