728x90
반응형
728x90

 

컴포넌트 문법

 

React에서 HTML을 컴포넌트화하여 App.js 파일에 작성하는 것은 매우 일반적인 방법입니다. 이렇게 하면 코드를 재사용하고 유지보수하기 쉽게 만들 수 있습니다.

컴포넌트는 반복적인 html을 작성 시 or 내용이 많이 담기는 페이지를 만들 때 or 자주 변경되는 페이지들을 컴포넌트 문법을 사용해서 만드는 게 좋습니다.

1단계 : function 만들어 줍니다.  2단계 : return( ) 안에 html태그를 작성  3단계 : <함수명></함수명>

		import React from 'react';
		
		function FirstComponent() {
		  return (
		    <div>
		      <h1>Hello, World!</h1>
		      <p>내 첫 컴포넌트야 ! </p>
		    </div>
		  );
		}
		
		export default FirstComponent;

**위의 코드에서 FirstComponent는 함수형 컴포넌트로, 간단한 헤더와 문단을 렌더링합니다.
다음으로, 이 컴포넌트를 App.js 파일에서 import하여 사용할 수 있습니다.**

 

 

		import React from 'react';
		import FirstComponent from './FirstComponent'; // FirstComponent 컴포넌트를 import합니다.
		
		function App() {
		  return (
		    <div className="App">
		      <h1>나의 첫 리액트 앱에 방문해줘서 고마!</h1>
		      <FirstComponent /> {/* FirstComponent를 여기에서 사용합니다. */}
		    </div>
		  );
		}
		
		export default App;

 

위의 코드에서 MyComponent를 App 컴포넌트 내에서 사용하고 있습니다. 이렇게 하면 MyComponent 컴포넌트의 UI가 App 컴포넌트 안에 렌더링됩니다.

또한, 다른 컴포넌트들도 동일한 방식으로 만들어서 App.js 파일에서 사용할 수 있습니다. 이렇게 함으로써 큰 애플리케이션을 여러 작은 컴포넌트로 나누어 개발할 수 있습니다.

 


 

 

동적인 UI 만들어보기

 

 

동적인 UI는 대표적으로 툴팁 , 모달 페이지 등이 있습니다. React에서 동적인 UI를 만드는 방법은 주로 상태와 이벤트 처리를 활용하는 것에 있습니다.

기본적으로 먼저 html css로 미리 디자인을 완성한 후 UI의 현재 상태를 state로 저장하여 state에 따라 조건을 부여한 후 해당 조건이 변경됨에 따라 UI에 변화를 발생시켜 동적으로 기능하게 만들 수 있습니다.

 

1. state를 활용한 동적 UI 만들기

import React, { useState } from 'react';

function DynamicUI() {
  const [count, setCount] = useState(0);

  const handleIncrement = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={handleIncrement}>Increment</button>
    </div>
  );
}

export default DynamicUI;

 

state는 컴포넌트의 동적인 데이터를 관리하는 데 사용됩니다. useState 훅을 사용하여 함수형 컴포넌트에서 상태를 선언할 수 있습니다.

 

2. 이벤트 처리를 활용한 동적 UI 만들기

import React, { useState } from 'react';

function DynamicInput() {
  const [inputValue, setInputValue] = useState('');

  const handleInputChange = (e) => {
    setInputValue(e.target.value);
  };

  return (
    <div>
      <input type="text" value={inputValue} onChange={handleInputChange} />
      <p>You typed: {inputValue}</p>
    </div>
  );
}

export default DynamicInput;

 

React에서 이벤트 처리는 일반적인 JavaScript와 유사합니다. 이벤트 핸들러 함수를 정의하고 JSX에서 해당 함수를 이벤트에 연결합니다. 아의 예제에서 handleInputChange 함수는 input 요소의 onChange 이벤트에 연결되어 입력값을 상태에 업데이트합니다.

 

동적 UI를 만들 때 가장 흔하게 사용하는 삼항 연산자에 대해서 설명드리자면, React에서 삼항 연산자(ternary operator)는 조건부 렌더링을 할 때 매우 유용하게 사용됩니다. 삼항 연산자는 조건이 참이면 A를 반환하고, 그렇지 않으면 B를 반환하는 간단한 문법을 가지고 있습니다.

 

일반적으로 JSX에서 삼항 연산자를 사용하여 조건부로 요소를 렌더링합니다. 예를 들어, 로그인 유무에 따라 페이지의 상태 변화를 주기 위해 isLoggedIn이라는 상태가 있고 이 값에 따라 다른 환영 메시지를 렌더링하고 싶다고 가정해보겠습니다.

                import React from 'react';

                function Hello() {

                const [isLoggedIn, setIsLoggedIn] = useState(false);

                  return (
                    <div>
                      {isLoggedIn ? (
                        <h1>반가워 !</h1>
                      ) : (
                        <h1>회원 가입을 부탁드립니다.</h1>
                      )}
                    </div>
                  );
                }

                export default Hello;

 

위의 코드에서 삼항 연산자를 사용하여 isLoggedIn 값이 true이면 "반가워 !"을, 그렇지 않으면 "회원 가입을 부탁드립니다."을 렌더링합니다. JSX 코드 내에서 삼항 연산자를 중괄호 **{}**로 둘러싸는 것에 주의해야 합니다.

삼항 연산자는 조건이 더 복잡한 경우에도 사용할 수 있습니다. 예를 들어, isLoggedIn이 true일 때와 isAdmin이 true일 때 각각 다른 메시지를 보여주고 싶다면 다음과 같이 할 수 있습니다

            import React from 'react';

            function Hello() {

            const [isLoggedIn, setIsLoggedIn] = useState(false);

              return (
                <div>
                  {isLoggedIn ? (
                    isAdmin ? (
                      <h1>관리자 계정으로 접속하셨습니다.</h1>
                    ) : (
                      <h1>반가워 !</h1>
                    )
                  ) : (
                    <h1>회원 가입을 부탁드립니다.</h1>
                  )}
                </div>
              );
            }

            export default Hello;

 

이렇게 함으로써 여러 조건에 따라 동적으로 UI를 렌더링할 수 있습니다. 삼항 연산자는 React 컴포넌트에서 조건부 렌더링을 위해 자주 사용되는 패턴 중 하나입니다. onClick 이벤트와 삼항연산자를 함께 사용하면 버튼처럼 isLogined의 상태가 true , false를 반복하게 됩니다.

 


 

💡 React에서의 Map( ) 함수

 

map 함수는 JavaScript 배열에서 사용되며 배열의 각 요소에 대해 주어진 함수를 호출하고 그 결과로 새로운 배열을 반환합니다.

이를 통해 각 요소를 변형하거나 가공하여 새로운 배열을 생성할 수 있습니다. React에서는 map 함수를 주로 배열의 요소를 기반으로 컴포넌트를 동적으로 생성하는 데 사용됩니다.

 

            const newArray = Array.map((element, index, array) => {
              return newArray.element;
            });

            ****element: 배열의 현재 요소
            index: 배열의 현재 요소의 인덱스
            array: map 함수가 호출된 배열 자체

            **[1,2,3].map(function() {
                    [1,2,3]은 array인데, 해당 array 자료 갯수만큼 함수 내부의 코드를 실행함
                return '123456' 
                    => return 값을 해당 배열안에 담아줍니다.

            })**

map 함수는 각 요소에 대해 주어진 콜백 함수를 호출하고 그 함수의 반환값들을 새로운 배열로 반환합니다.

예제 -

        const numbers = [1, 2, 3, 4, 5];

        const NumbersA = numbers.map((number) => {
          return number * number;
        });

        **console.log(NumbersA); // 출력: [1, 4, 9, 16, 25]

        위의 예제에서 map 함수는 numbers 배열의 각 요소를 제곱하여 새로운 배열 squaredNumbers를 생성합니다.**

 

React에서의 활용

React에서 map 함수는 주로 동적으로 컴포넌트를 생성할 때 사용됩니다. 예를 들어, 배열의 각 요소를 기반으로 리스트를 생성하는 경우:

            import React from 'react';

            function Component() {
              const items = ["Item 1", "Item 2", "Item 3", "Item 4"];

              return (
                <ul>
                  {items.map((item, index) => (
                    <li key={index}>{item}</li>
                  ))}
                </ul>
              );
            }

 

위의 예제에서 map 함수는 items 배열의 각 요소에 대해 <li> 요소를 생성하여 동적으로 리스트를 만듭니다. key 속성은 React가 각 항목을 구별하는 데 사용됩니다.

이러한 방식으로 map 함수를 사용하면 배열의 각 요소를 기반으로 동적인 UI를 쉽게 생성할 수 있습니다.

 

Map 예제들

            const users = [
               { id : 1, name: "superman"},
               { id : 2, name : "pubao"},
               { id : 3, name : "kwonnnn"} ];

            const userNames = users.map((user) => {
              return user.name;
            })

            console.log(userNames);

             **출력 결과 => (3) ['superman', 'pubao', 'kwonnnn']

            ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ**

            const numbers = [1, 2, 3, 4, 5];

            const squaredNumbers = numbers.map((number) => {
              return number * number;
            });

            **console.log(squaredNumbers); // 출력: [1, 4, 9, 16, 25]

            ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ**

            const numbers = [1, 2, 3, 4, 5, 6];

            const oddEvenNumbers = numbers.map((number) => {
              return number % 2 === 0 ? 'even' : 'odd';
            });

            **console.log(oddEvenNumbers); // 출력: ["odd", "even", "odd", "even", "odd", "even"]**
728x90
반응형

'[FRONTEND] > REACT' 카테고리의 다른 글

[REACT] 기본 문법_Object 자료형 , Route  (1) 2023.10.22
[REACT] 기본 문법_Props !  (1) 2023.10.20
[REACT] 기본문법  (0) 2023.10.05
[REACT] 시작하기  (1) 2023.10.03
[REACT] REACT 시작하기  (0) 2023.10.03
728x90

 

정보처리기사 실기시험을 준비하면서 개인적으로 정리한 학습 내용 ✍️

 


 

UI 화면 설계를 위한 산출물

  • 와이어 프레임 : 이해 관계자들과의 화면 구성을 협의하거나 서비스의 간략한 흐름을 공유하기 위해 화면 단위의 레이아웃을 설계하는 작업
  • 스토리보드 : 정책, 프로세스, 콘텐츠 구성, 와이어 프레임, 기능 정의, 데이터베이스 연동 등 서비스 구축을 위한 모든 정보가 담겨져 있는 설계 산출물
  • 프로토타입 : 정적인 화면으로 설계된 와이어 프레임 또는 스토리보드에 동적 효과를 적용하여 실제 구현된 것처럼 시뮬레이션을 할 수 있는 모형

 

객체 지향 설계원칙(SOLID)

  1. 단일 책임의 원칙(Single Responsibility Principle) : 하나의 클래스는 하나의 목적을 위해서 생성되며, 클래스가 제공하는 모든 서비스는 하나의 책임을 수행하는데 집중되어 있어야 한다는 원칙
  2. 개방 폐쇄의 원칙 (Open Close Principle) : 소프트웨어의 구성요소 (컴포넌트,클래스,모듈,함수)는 확장에는 열려있고, 변경에는 닫혀 있어야 한다는 원칙
  3. 리스코프 치환의 원칙(Liskov Substitution Principle) : 서브타입 (상속받은 하위 클래스)은 어디서나 자신의 기반 타입(상위클래스)로 교체할 수 있어야 한다는 원칙
  4. 인터페이스 분리의 원칙(Interface Segregation Principle) : 한 클래스는 자신이 사용하지 않는 인터페이스는 구현하지 말아야 한다는 원칙 / 클라이언트가 사용하지 않는 인터페이스 때문에 영향을 받아서는 안된다는 원칙
  5. 의존성 역전의 원칙 (Dependency Inversion Principle) : 실제 사용 관계는 바뀌지 않으며, 추상을 매개로 메세지를 주고 받음으로써 관계를 최대한 느슨하게 만드는 원칙

 

 

🌟 결합도(Coupling) 🌟: 결합도는 모듈 내부가 아닌 외부의 모듈과의 연관도 또는 모듈 간의 상호의존성을 의미하며, 결합도가 낮을수록 품질이 좋아짐 (내공외제스자 → 결합도 낮은 방향 _자료가 제일 좋음)

  1. 내용 결합도(Content) : 다른 모듈 내부에 있는 변수나 기능을 다른 모듈에서 사용하는 경우의 결합도
  2. 공통 결합도(Common) : 파라미터가 아닌 모듈 밖에 선언되어있는 전역 변수를 참조하고 전역 변수를 갱신하는 식으로 상호작용하는 경우의 결합도
  3. 외부 결합도(External) : 두 개의 모듈이 외부에서 도입된 데이터 포맷, 통신 프로토콜 또는 디바이스 인터페이스를 공유할 경우의 결합도
  4. 제어 결합도(Control) : 단순 처리할 대상인 값만 전달되는 게 아니라 어떻게 처리를 해야한다는 제어 요소가 전달되는 경우의 결합도
  5. 스탬프 결합도(Stamp) : 모듈간의 인터페이스로 배열이나 객체 , 구조 등이 전달되는 경우의 결합도
  6. 자료 결합도(Data) : 모듈간의 인터페이스로 전달되는 파라미터를 통해서만 모듈간의 상호작용이 일어나는 경우의 결합도

 

🌟응집도 (Cohesion) 🌟  : 모듈의 독립성을 나타내는 정도로, 모듈 내부 구성요소 간 연관 정도 / 응집도가 높을 수록 품질이 좋음(우논시절통순기 → 응집도가 높은 방향_기능적 응집도가 제일 좋음)

  1. 우연적 응집도(Coincidental Cohesion) : 모듈 내부의 각 구성요소가 연관이 없을 경우의 응집도
  2. 논리적 응집도(Logical Cohesion) : 유사한 성격을 갖거나 특정 형태로 분류되는 처리 요소들이 한 모듈에서 처리되는 경우의 응집도
  3. 시간적 응집도(Temporal Cohesion) : 연관된 기능이라기보다는 특정 시간에 처리되어야 하는 활동들을 한 모듈에서 처리할 경우의 응집도
  4. 절차적 응집도(Procedural Cohesion) : 모듈이 다수의 관련 기능을 가질 때 모듈안의 구성요소들이 그 기능을 순차적으로 수행할 경우의 응집도
  5. 통신적 응집도(Communication Cohesion) : 동일한 입력과 출력을 사용하여 다른 기능을 수행하는 활동들이 모여있을 경우의 응집도
  6. 순차적 응집도(Sequential Cohesion) : 모듈 내에서 한 활동으로부터 나온 출력값을 다른 활동이 사용할 경우의 응집도
  7. 기능적 응집도(Functional Cohesion) : 모듈 내부의 모든 기능이 단일한 목적을 위해 수행되는 경우의 응집도

 

UML 다이어그램 : 구조적(정적) 다이어그램 - 객체지향 소프트웨어 개발 과정에서 산출물을 병세화, 시각화, 문서화할 때 사용되는 모델링 기술과 방법론을 통합해서 만든 표준화 된 언어

  • 클래스 다이어그램 : 객체지향 모델링 시 클래스의 속성 및 연산과 클래스 간 정적인 관계를 표현한 다이어그램 클래스 다이어그램의 구성요소 
    클래스→속성,메서드,관계,의미를 공유하는 객체들의 집합 ,
    속성→
    구조적 특성에 이름을 붙인 것 ,
    연산(메서드) →
    행위적 특징, 접근제어자→ 클래스에 접근할 수 있는 정도
  • 객체 다이어그램 : 클래스에 속한 사물(객체)들, 즉 인스턴스를 특정 시점의 객체와 객체 사이의 관계로 표현한 다이어그램 / 연관된 모든 인스턴스를 표현
  • 컴포넌트 다이어그램 : 시스템을 구성하는 물리적인 컴포넌트와 그들 사이의 의존 관계를 나타내 다이어그램
  • 배치 다이어그램 : 컴포넌트 사이의 종속성을 표현하고, 그 결과물 , 프로세스, 컴포넌트 등 물리적 요소들의 위치를 표현하는 다이어그램
  • 복합체 구조 다이어그램 : 클래스나 컴포넌트가 복합 구조를 갖는 경우 그 내부 구조를 표현하는 다이어그램
  • 패키지 다이어그램 : 유스케이스나 클래스 등의 모델 요소들을 그룹화한 패키지들의 관계를 표현한 다이어그램

 

UML의 관계

  • 집합 관계 : 하나의 객체에 여러 개의 독립적인 객체들이 구성되는 관계 / 하나의 사물이 다른 사물에 포함되어 있는 관계를 표현 , 포함되는 쪽(부분)에서 포함하는 쪽(전체)으로 속이 빈 마름모를 연결하여 표현 (ex.차와 엔진, 바퀴, 운전대)
  • 복합 관계 : 영구적이고 , 집합관계보다 더 강한 관계로 구성 / 포함되는 쪽(부분)에서 포함하는 쪽(전체)으로 속이 채워진 마름모를 연결하여 표현 , 복합 관계는 집합관계의 특수한 형태로 포함하는 사물의 변화가 포함되는 사물에 영향을 미치는 관계
728x90
반응형
728x90

 React의 이벤트 핸들러

 

React에서 이벤트 핸들러를 다룰 때, 보통 다양한 이벤트 핸들러를 사용할 수 있습니다.

   1. `onClick` 이벤트 핸들러

    onClick 이벤트 핸들러는 **사용자가 클릭할 때 실행됩니다. 아래의 예시에서 handleClick 메서드는 버튼이 클릭될 때 호출됩니다

			import React from 'react';
			
			const Component = () => {
			  const handleClick = () => {
			    console.log('Button clicked!');
			  };
			
			  return <button onClick={handleClick}>Click Me</button>;
			};
			
				export default Component;

 

2. onChange 이벤트 핸들러

		import React, { useState } from 'react';
		
		const Component = () => {

		  const [inputValue, setInputValue] = useState('');
		
		  const handleChange = (event) => {
		    setInputValue(event.target.value);
		    console.log('입력 값이 변경되었습니다:', event.target.value);
		  };
		
		  return <input type="text" value={inputValue} onChange={handleChange} />;
		};

 

 

onChange 이벤트 핸들러는 사용자가 입력 필드나 선택 옵션을 변경할 때 실행됩니다. 아래의 예시에서 handleChange 메서드는 입력 필드의 값이 변경될 때 호출됩니다

3. onSubmit 이벤트 핸들러

		import React from 'react';
		
		const Component = () => {
		  const handleSubmit = (event) => {
		    event.preventDefault();
		    console.log('제출 완료 !');
		  };
		
		  return (
		    <form onSubmit={handleSubmit}>
		      <button type="submit">Submit</button>
		    </form>
		  );
		};

 

onSubmit 이벤트 핸들러는 폼(form)이 제출될 때 실행됩니다. 아래의 예시에서 handleSubmit 메서드는 폼이 제출될 때 호출됩니다

 


💡 State의 특징

 

🌟 React에서 상태를 업데이트할 때, 새로운 상태를 만들기 위해 불변성(Immutability)을 유지해야 합니다. 이렇게 함으로써 React는 상태의 변화를 감지하고 적절한 업데이트를 수행할 수 있습니다.

만약 기존 상태와 새로운 상태가 동일하다면(값이 같다면), React는 이를 최적화하여 렌더링을 방지할 수 있습니다. React에서 상태를 업데이트할 때
상태 변경 함수에 전달하는 인자가 이전 상태와 동일하다면, React는 렌더링을 건너뛰어 성능을 최적화합니다.

그러나 주의해야 할 점은 객체나 배열과 같은 복합 데이터 타입을 다룰 때입니다. 객체나 배열은 참조 타입이기 때문에 동일한 내용을 가지더라도 메모리에 저장된 위치가 다를 수 있습니다.
따라서 객체나 배열의 경우 새로운 객체 또는 배열을 생성하여 업데이트해야 합니다.

const [user, setUser] = useState({ name: '푸바오', age: 10 });

const handleAgeChange = () => {
  setUser({ ...user, age: user.age + 1 }); // 이전 상태와 동일한 내용을 갖는 새로운 객체를 생성하여 업데이트합니다.
};

 

위의 코드에서 setUser({ ...user, age: user.age + 1 })는 이전 상태의 내용을 유지한 새로운 객체를 생성하면서 나이 필드를 업데이트합니다. 이렇게 하면 React는 상태가 실제로 변경되었음을 감지하고 렌더링을 수행합니다.

 


Spread Operator (스프레드 연산자)

 

[...data]는 JavaScript의 스프레드 연산(Spread Operator)입니다. 이 연산자는 배열이나 객체의 요소들을 개별 요소로 분해하거나 복사할 때 사용됩니다.

React에서 주로 사용되는 상황 중 하나는 상태(State)나 프로퍼티(Props)를 업데이트할 때 이 연산자를 사용하여 배열을 수정하는 것입니다.

  ✍️ 배열에 새로운 요소를 추가하거나 기존 요소를 제거하면서 배열을 변경하고 싶을 때 확산 연산자를 사용할 수 있습니다.**

    const newData = [...data, newItem];

위 코드는 data 배열의 모든 요소를 펼쳐서(...data) 새로운 배열을 생성하고, 그 뒤에 newItem을 추가한 새로운 배열을 만듭니다. 기존 배열 data를 변경하지 않고 새로운 배열을 생성하는 것이기 때문에 불변성(Immutability)을 유지하게 됩니다.

 

또한, 배열에서 요소를 제거하고 싶을 때도 확산 연산자를 사용할 수 있습니다. 예를 들어, 특정 요소를 제거한 새로운 배열을 생성하고자 할 때는 다음과 같이 사용할 수 있습니다

   ✍️ data 배열에서 idToRemove와 일치하지 않는 요소들만 남겨서(filter 함수를 사용) 새로운 배열을 생성합니다.**

        const updatedData = data.filter(item => item.id !== idToRemove);

 

스프레드 연산자는 객체에서도 사용할 수 있습니다. 객체의 속성을 복사하거나 새로운 속성을 추가하고자 할 때 사용됩니다. 객체에서의 사용법은 다음과 같습니다

const originalObject = { key1: 'value1', key2: 'value2' };
const updatedObject = { ...originalObject, newKey: 'newValue' };

✍️ originalObject 객체의 모든 속성을 복사하여(...originalObject) 새로운 객체를 생성하고, 
    그 뒤에 newKey와 newValue 속성을 추가한 새로운 객체를 만듭니다.

 

 

728x90
반응형

'[FRONTEND] > REACT' 카테고리의 다른 글

[REACT] 기본 문법_Object 자료형 , Route  (1) 2023.10.22
[REACT] 기본 문법_Props !  (1) 2023.10.20
[REACT] 기본 문법_컴포넌트 문법 & Map( ) 함수  (0) 2023.10.12
[REACT] 시작하기  (1) 2023.10.03
[REACT] REACT 시작하기  (0) 2023.10.03
728x90

 

📋 JSX란 ?

 

JSX(JavaScript XML)는 React에서 사용되는 자바스크립트의 확장 문법입니다. JSX는 React 애플리케이션에서 UI를 표현하기 위해 사용됩니다.
JSX는 마치 HTML과 유사한 구문을 사용하여 UI 구성 요소를 작성할 수 있게 해줍니다. JSX 코드는 React 엘리먼트를 생성하며, React 엘리먼트는 사용자 인터페이스의 구성 요소입니다.

일반적인 JSX 구문은 다음과 같습니다 ⇒ const title = <h1>Hello, World!</h1>;

JSX의 특징

  1. HTML과 유사한 구문: JSX는 HTML과 매우 유사한 문법을 가지고 있어 익숙한 형태로 UI를 작성할 수 있습니다.

  2. JavaScript 표현식 포함: {} 중괄호 안에서 JavaScript 표현식을 사용할 수 있습니다. 이를 통해 동적인 값을 JSX에 포함시킬 수 있습니다. ex ) const name = "React"; const element = <h1>Hello, {name}!</h1>;

  3. 속성 지정: HTML 요소에 속성을 지정할 수 있습니다. JSX에서는 속성에 값을 할당할 때 중괄호를 사용하여 JavaScript 표현식을 사용할 수 있습니다. ex ) const imageUrl = "example.jpg"; const element = <img src={imageUrl} alt="Example" />;

  4. JSX는 표현식: JSX는 표현식이므로 변수에 할당하고, 함수의 인자로 전달하고, 조건문과 반복문 안에서 사용할 수 있습니다. 이를 통해 동적인 UI를 쉽게 만들 수 있습니다.

  5. 클래스 이름 지정: class 키워드를 사용할 수 없기 때문에 JSX에서는 **className**을 사용하여 HTML 요소에 클래스 이름을 지정할 수 있습니다 ex ) const element = <div className="my-class">Hello, World!</div>;

 

JSX는 React 애플리케이션에서 UI를 빌드하는 강력한 도구로, 코드의 가독성을 높이고 유지보수를 쉽게 만들어줍니다. React에서 컴포넌트를 작성할 때 JSX를 활용하면 간결하고 효과적인 UI 코드를 작성할 수 있습니다.

 


 

🎈 React JSX 기본 문법

 

            import React from 'react';

            function App() {

                    return (
                        <div>
                            <h1>Hello, World!</h1>
                            <p>Hello, World에 오신 걸 환영합니다</p>
                        </div>
                    );
            }

            export default App;

 

화면에 보여지게 하고 싶은 html 태그는 꼭 return 문 안에 작성되어야 합니다. 해당 코드는 React 함수형 컴포넌트인 App을 정의하고 있습니다.
이 컴포넌트는 JSX 문법을 사용하여 UI를 정의하고 있습니다. 여기에서 return 문 안에 작성된 JSX가 컴포넌트의 출력 결과를 결정합니다.

return 문안에 작성되어야 하는 이유는 아래와 같습니다.

  1. UI 정의: return 문 안의 JSX는 컴포넌트가 렌더링할 UI를 정의합니다. 컴포넌트의 주된 역할은 사용자에게 보여지는 UI를 생성하는 것이기 때문에 JSX를 사용하여 UI를 정의합니다.

  2. 가독성: JSX를 사용하면 UI 구조를 직관적이고 가독성 있게 표현할 수 있습니다. HTML과 유사한 문법을 사용하므로, 컴포넌트의 UI가 어떻게 보이는지 빠르게 파악할 수 있습니다.

  3. 재사용성: JSX를 사용하면 컴포넌트를 쉽게 재사용할 수 있습니다. 여러 컴포넌트에서 동일한 JSX 구조를 사용하여 일관된 UI를 구성할 수 있습니다.

  4. 동적 데이터 삽입: JSX 안에서 중괄호 {}를 사용하여 JavaScript 표현식을 넣을 수 있습니다. 이를 통해 동적인 데이터를 UI에 삽입할 수 있습니다. 예를 들어, {props.name}과 같이 프로퍼티를 사용하여 동적 데이터를 표시할 수 있습니다.

  5. React 엘리먼트 생성: JSX를 사용하면 React 엘리먼트를 생성할 수 있습니다. React 엘리먼트는 실제 DOM 엘리먼트와 매핑되며, React가 이를 사용하여 가상 DOM을 구성하고 렌더링을 최적화합니다.

따라서 return 문 안에 JSX를 작성함으로써 React 함수형 컴포넌트는 어떻게 화면에 렌더링될지를 정의하게 되며, 이는 React의 핵심 원칙 중 하나인 "UI는 상태(state)에 의존적이어야 한다"를 충족시키기 위한 방법입니다.

💥 또 하나의 주의점은 React 컴포넌트에서 return 문 안에 병렬로 여러 개의 div 태그를 작성하면 컴파일 오류가 발생합니다. JSX는 하나의 부모 엘리먼트로 묶여있어야 하고, 그렇지 않으면 React가 컴포넌트의 렌더링을 처리할 때 모호성이 발생하게 되기 때문입니다.

 


 

 

 

✅ Destructuring 문법이란?

디스트럭처링(Destructuring)은 ECMAScript 6(ES6)에서 추가된 JavaScript 문법 중 하나입니다. 이 문법은 배열이나 객체에서 데이터를 추출하여 변수에 할당하는 간단한 방법을 제공합니다. 이를 통해 코드를 더 간결하고 가독성 있게 작성할 수 있습니다.

 

 1. Array Destructuring

            const numbers = [1, 2, 3, 4, 5];
                const [first, second] = numbers;

                console.log(first); // 1
                console.log(second); // 2

        => 위의 코드에서 numbers 배열의 첫 번째 요소는 first 변수에, 두 번째 요소는 second 변수에 할당됩니다.

 

2. Object Distructuring 문법

                const person = {
                  name: '푸바오',
                  age: 10,
                  city: 'Korea'
                };

                const { name, age } = person;

                console.log(name); // '푸바오'
                console.log(age); // 10

        => 위의 코드에서 person 객체의 name 속성은 name 변수에, age 속성은 age 변수에 할당됩니다.

 

3. Parameter Distructuring

                const person = {
                  name: '푸바오',
                  age: 10
                };

                function displayAnimal({ name, age }) {
                  console.log(`Name: ${name}, Age: ${age}`);
                }

                displayPerson(person); // 출력: Name: 푸바오, Age: 10
        => 위의 코드에서 displayAnimal 함수의 매개변수에서 객체 디스트럭처링을 사용하여 객체의 속성을 추출합니다.

 

Distructuring (디스트럭처링)은 복잡한 데이터 구조에서 특정 값을 추출하거나, 함수의 매개변수로 전달된 객체나 배열에서 필요한 값을 간편하게 추출할 때 유용합니다. 이를 통해 코드의 가독성을 높이고, 필요한 데이터를 쉽게 다룰 수 있습니다.

 


 

React에서의 state와 state 사용

 

React의 state란 컴포넌트의 상태를 저장하고 변경할 때 사용되며, 주로 사용자 인터랙션에 응답하여 UI를 업데이트하거나 비동기 작업 결과를 처리할 때 활용됩니다. React에서 state를 사용해야 하는 시점컴포넌트의 내부 데이터를 관리하고 동적인 UI를 구현해야 할 때입니다.

  • 사용자 입력 처리: 사용자가 폼을 작성하거나 버튼을 클릭하는 등의 사용자 입력에 대한 응답으로 state를 사용할 수 있습니다. 예를 들어, 입력 필드에 사용자가 입력한 값을 state에 저장하여 렌더링할 때 사용됩니다.

  • 외부 데이터 불러오기: 외부 API 호출 또는 데이터베이스에서 데이터를 불러올 때 비동기 작업의 결과를 state에 저장하여 UI를 업데이트할 수 있습니다. 데이터가 로드되면 컴포넌트의 state를 업데이트하고, 이를 기반으로 UI를 렌더링할 수 있습니다.

  • 동적 UI 업데이트: 어떤 조건에 따라 UI를 동적으로 업데이트해야 할 때 state를 사용할 수 있습니다. 예를 들어, 버튼 클릭에 따라 토글되는 상태를 관리하거나, 조건에 따라 다른 컴포넌트를 렌더링하는 등의 상황에서 state를 사용할 수 있습니다.

 

이러한 상황에서 state를 사용하여 컴포넌트의 동적인 동작과 UI 업데이트를 관리할 수 있습니다. 단, state는 컴포넌트의 지역 상태로서 해당 컴포넌트에서만 사용될 수 있으며, 필요한 경우 props로 다른 컴포넌트에 전달할 수 있습니다.

여기서 주의할 점은 모든 데이터를 state 값으로 사용하는 것이 아니라 주로 컴포넌트 내에서 변경될 수 있는 값을 관리하기 위해 사용해야 합니다. 이 말은 컴포넌트의 상태가 변할 때만 state를 사용해야 한다는 것을 의미합니다.
즉, 사용자 입력, API 호출 결과, 컴포넌트의 내부 동적 상태 등 컴포넌트가 직접 관리해야 하는 값들이 state로 관리됩니다.

그러나 모든 값이 state로 들어가면 안 되며, 컴포넌트 내에서 변하지 않는 값은 state로 관리하지 않아야 합니다. 예를 들어, props로 전달된 값이나, 컴포넌트 내부에서 계산된 값을 state에 저장할 필요가 없습니다.
또한, state를 사용할 때는 해당 state 값을 직접적으로 변경해서는 안 됩니다. 대신, setState 메서드를 사용하여 state를 업데이트해야 합니다.


 

React에서 setState() 함수는 비동기적으로 동작합니다. 이것은 setState() 호출이 즉시 상태를 업데이트하지 않고, React 엔진이 성능 최적화 및 일괄 처리를 위해 업데이트를 지연시키기 때문입니다. 이러한 비동기적 특성은 React의 성능을 향상시키고 예상치 못한 동작을 방지하기 위해 존재합니다.

이러한 비동기 동작은 다음과 같이 영향을 미칠 수 있습니다:

       
       	
       
       	class MyComponent extends React.Component {
              constructor(props) {
                super(props);
                this.state = {
                  count: 0,
                };
              }

              handleButtonClick = () => {
                this.setState({ count: this.state.count + 1 });
                console.log(this.state.count); // 이 값은 업데이트 이전의 상태를 보여줍니다.
              };

              render() {
                return (
                  <div>
                    <p>Count: {this.state.count}</p>
                    <button onClick={this.handleButtonClick}>증가</button>
                  </div>
                );
              }
            }

 

위 코드에서 handleButtonClick 메서드는 버튼 클릭시 count 상태를 1 증가시키려고 합니다.  console.log(this.state.count)에서 출력되는 값은 업데이트 이전의 상태입니다. 이는 setState()가 비동기적으로 동작하기 때문입니다.

 

      
	해결 방법
	1. setState() 함수의 두 번째 매개변수로 콜백 함수를 전달하여 상태 업데이트가 완료된 후에 코드를 실행할 수 있습니다.
      
       	handleButtonClick = () => {
              this.setState({ count: this.state.count + 1 }, () => {
                console.log(this.state.count); // 업데이트 이후의 상태를 출력합니다.
              });
            };
            
            
            
            
            
	2. 함수형 업데이트 사용:
	setState() 함수에 함수를 전달하여 이전 상태를 기반으로 새로운 상태를 계산할 수 있습니다. 이 방법은 이전 상태를 정확하게 기반으로 업데이트할 수 있도록 보장합니다.


        handleButtonClick = () => {
          this.setState((prevState) => {
            return { count: prevState.count + 1 };
          }, () => {
            console.log(this.state.count); // 업데이트 이후의 상태를 출력합니다.
          });
        };

 

둘 다 업데이트 이후의 상태를 보장하므로 비동기적인 특성에 대응할 수 있습니다. 주로 두 번째 방법(함수형 업데이트)이 권장되며, 이전 상태를 정확하게 기반으로 업데이트할 수 있도록 도와줍니다.

728x90
반응형

'[FRONTEND] > REACT' 카테고리의 다른 글

[REACT] 기본 문법_Object 자료형 , Route  (1) 2023.10.22
[REACT] 기본 문법_Props !  (1) 2023.10.20
[REACT] 기본 문법_컴포넌트 문법 & Map( ) 함수  (0) 2023.10.12
[REACT] 기본문법  (0) 2023.10.05
[REACT] REACT 시작하기  (0) 2023.10.03
728x90

💡 React란 ?

 

React는 Facebook에서 개발한 사용자 인터페이스를 만들기 위한 JavaScript 라이브러리입니다. 웹 애플리케이션의 사용자 인터페이스를 만들기 위해 활용되며, 특히 단일 페이지 애플리케이션(SPA) 개발에 많이 사용됩니다.

React는 사용자 인터페이스를 구성하는 데 필요한 컴포넌트 기반 아키텍처를 사용합니다. 각 컴포넌트는 재사용 가능하며, 이러한 컴포넌트들을 조합하여 복잡한 사용자 인터페이스를 만들 수 있습니다.
React는 가상 DOM(Virtual DOM)이라는 개념을 도입하여 성능을 최적화하고, 변경된 부분만 실제 DOM에 적용하여 렌더링 성능을 향상시킵니다.


🎈 REACT 설치 및 실행

 

1. Node.js 다운로드

 

https://nodejs.org/ko

React를 사용하기 위해 해당 링크에 접속해서 Node.js 설치를 해야합니다.

두 가지 버전을 다운받을 수 있는데 LTS가 붙은 버전은 기업에서 사용해도 될만큼 안정화되었고 신뢰도가 높은 버전이고 오른쪽의 현재 버전은 현재 버전으로 최신 기능들을 이용할 수 있으나 안정성과 신뢰성이 낮습니다.

 

Node.js 다운로드

 

다운로드 받은 Node.js 설치 진행

 

 

 

 

설치가 완료된 후 터미널을 실행하여 node -v을 입력한 후 node.js의 버전을 확인합니다.

 

 

2. React프로젝트 생성

 

React 프로젝트를 실행 할 폴더를 생성하고 해당 폴더로 이동합니다. 해당 폴더의 터미널에 npx create-react-app 프로젝트명을 입력하여, react 프로젝트를 설치합니다.

npx create-react-app haneep-react 를 터미널에 입력하여 프로젝트명이 haneep-react인 react 프로젝트를 생성

 

 

명령프롬포트에 입력하면 약 30초 ~ 1분 가량 설치가 진행되고, 설치가 완료되면 해당 화면이 cmd창 하단에 Happy hacking이라는 문구가 나타나게 됩니다.

이 후 터미널에 npm start를 입력하면 react 프로젝트가 실행됩니다.

 

 

React는 웹 애플리케이션뿐만 아니라 모바일 애플리케이션 개발을 위한 React Native와 같은 파생 프레임워크도 제공하여 다양한 플랫폼에서 사용자 인터페이스를 구축할 수 있습니다.

728x90
반응형

'[FRONTEND] > REACT' 카테고리의 다른 글

[REACT] 기본 문법_Object 자료형 , Route  (1) 2023.10.22
[REACT] 기본 문법_Props !  (1) 2023.10.20
[REACT] 기본 문법_컴포넌트 문법 & Map( ) 함수  (0) 2023.10.12
[REACT] 기본문법  (0) 2023.10.05
[REACT] 시작하기  (1) 2023.10.03
728x90

 

🎈 서블릿으로 회원 관리 웹 어플리케이션 만들기


 

👉 MemberForm 서블릿을 생성하여 회원을 등록할 수 있는 로직을 서블릿으로 작성

        -> 회원 등록용 html form을 서블릿을 통해서 볼 수 있도록 설정
        @WebServlet(name="memberFormServlet", urlPatterns = "/servlet/members/new-form")
        public class MemberFormServlet extends HttpServlet {

            private MemberRepository memberRepository = MemberRepository.getInstance();
                -> 싱글톤이므로 new로 생성할 수 없기 때문에 getInstance()를 사용

            @Override
            protected void service(HttpServletRequest request, HttpServletResponse response) 
                                                                    throws ServletException, IOException {

                     -> contentType과 Encoding을 설정
                response.setContentType("text/html");
                response.setCharacterEncoding("utf-8");

                PrintWriter w = response.getWriter();
                w.write("<!DOCTYPE html>\n" +
                        "<html>\n" +
                        "<head>\n" +
                        " <meta charset=\"UTF-8\">\n" +
                        " <title>Title</title>\n" +
                        "</head>\n" +
                        "<body>\n" +
                        "<form action=\"/servlet/members/save\" method=\"post\">\n" +
                        " username: <input type=\"text\" name=\"username\" />\n" +
                        " age: <input type=\"text\" name=\"age\" />\n" +
                        " <button type=\"submit\">전송</button>\n" +
                        "</form>\n" +
                        "</body>\n" +
                        "</html>\n");
                        
            }
        }

 

위 코드에서 service 메서드는 HttpServlet 클래스의 메서드로, 클라이언트로부터 들어오는 모든 요청을 처리하는 역할을 합니다. 서블릿은 웹 애플리케이션에서 클라이언트와 서버 간의 통신을 담당하는 Java 클래스입니다.
서블릿은 HTTP 요청을 처리하여 동적인 웹 페이지를 생성하거나 데이터를 처리하는 데 사용됩니다.

HttpServlet 클래스는 GenericServlet 클래스를 상속받아서 만들어진 클래스로, HTTP 프로토콜을 사용하는 웹 애플리케이션에서 사용됩니다.
HttpServlet 클래스의 service 메서드는 HTTP 요청 방식(GET, POST, PUT, DELETE 등)에 따라 적절한 메서드(doGet, doPost, doPut, doDelete 등)를 호출하여 요청을 처리합니다.

예제에서 보여준 service 메서드는 클라이언트로부터 들어오는 모든 요청을 처리하고 있습니다. 먼저 response 객체를 이용하여 HTTP 응답을 설정합니다.
response.setContentType("text/html")은 응답으로 보낼 데이터의 MIME 타입을 설정하는 것이며, 여기서는 HTML 데이터를 전송한다는 의미입니다. response.setCharacterEncoding("utf-8")은 응답 데이터의 인코딩 방식을 설정합니다.

그리고 PrintWriter를 이용하여 HTML 형식의 응답 데이터를 작성합니다. 해당 HTML은 간단한 폼(form)을 생성하고, action 속성에 /servlet/members/save 경로로 요청을 보내도록 설정되어 있습니다.
save로 이동되어 회원이 저장된 코드를 볼 수 있는 로직을 작성해보겠습니다.

 


 

👉 SaveServlet을 생성하여 가입하는 회원의 데이터를 저장할 수 있는 로직을 서블릿으로 작성

        @WebServlet(name="memberSaveServlet", urlPatterns = "/servlet/members/save")
        public class MemberSaveServlet extends HttpServlet {

            private MemberRepository memberRepository = MemberRepository.getInstance();

            @Override
          -> form 에서 전송된 데이터를 getParameter로 꺼낸 후 비즈니스 로직 작성을 위해 member를 만든 후 save 함
            protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

                System.out.println(" MemberSaveServlet.service ");
                String username = request.getParameter("username");
                int age = Integer.parseInt(request.getParameter("age"));

                Member member = new Member(username, age);
                memberRepository.save(member);

            -> 결과는 html 형식으로 출력하기 위해 response.set으로 타입 설정 후, Printwriter객체로 작성 
                response.setContentType("text/html");
                response.setCharacterEncoding("utf-8");
                PrintWriter w = response.getWriter();
                w.write("<html>\n" +
                        "<head>\n" +
                        " <meta charset=\"UTF-8\">\n" +
                        "</head>\n" +
                        "<body>\n" +
                        "성공\n" +
                        "<ul>\n" +
                        " <li>id="+member.getId()+"</li>\n" +
                        " <li>username="+member.getUsername()+"</li>\n" +
                        " <li>age="+member.getAge()+"</li>\n" +
                        "</ul>\n" +
                        "<a href=\"/index.html\">메인</a>\n" +
                        "</body>\n" +
                        "</html>");
            }
        }

 

🎈 JSP로 회원 관리 웹 어플리케이션 만들기

 


 

JSP(JavaServer Pages)동적 웹 페이지를 생성하는 데 사용되는 서버 사이드 기술입니다. JSP는 HTML 문서 안에 Java 코드를 삽입하여 웹 페이지를 동적으로 생성하고, 서버 측에서 로직을 처리할 수 있도록 지원합니다.

JSP는 Java 코드와 HTML 코드를 혼합하여 작성할 수 있으며, 서블릿과 매우 유사한 구조를 가지고 있습니다. JSP 파일은 서블릿 클래스로 변환되어 실행됩니다.
웹 애플리케이션이 요청을 받으면 JSP 컨테이너가 해당 JSP 파일을 처리하여 자바 코드를 생성하고, 이 코드를 컴파일하여 서블릿 클래스를 생성한 뒤 실행합니다.

JSP의 주요 특징은 다음과 같습니다:

  1. 간편한 웹 페이지 작성: JSP는 HTML과 유사한 태그를 사용하여 동적 웹 페이지를 작성할 수 있습니다. Java 코드는 <% %> 태그로 삽입하여 사용할 수 있으며, ${ } 태그를 이용하여 변수 값을 출력할 수 있습니다.

  2. 서버 사이드 로직 지원: JSP는 서버 사이드에서 데이터를 처리하고 동적으로 페이지를 생성하는데 사용됩니다. 사용자 입력을 받아 처리하거나 데이터베이스와 상호작용하는 등의 로직을 쉽게 구현할 수 있습니다.

  3. MVC 디자인 패턴과의 통합: JSP는 Model-View-Controller (MVC) 디자인 패턴과 함께 사용하기 쉽습니다. 데이터 처리는 서블릿이나 자바 빈(Java Bean)에서 처리하고, JSP는 뷰(View) 역할을 담당합니다.

JSP는 주로 웹 애플리케이션의 프론트엔드를 구현하는 데 사용되며, 동적인 컨텐츠를 생성하는 데 적합합니다. 그러나 비즈니스 로직이나 데이터 처리 로직과 같은 백엔드 부분은 주로 서블릿이나 다른 백엔드 기술을 활용하여 구현하는 것이 일반적입니다.

JSP를 사용하면 개발자들은 웹 프로그래밍을 좀 더 쉽게 시작할 수 있으며, 더 빠르게 동적인 웹 페이지를 구현할 수 있습니다.
그러나 복잡한 로직이나 규모가 큰 웹 애플리케이션을 개발할 때는 JSP의 한계를 극복하기 위해 프레임워크(Spring, Struts 등)나 템플릿 엔진(Thymeleaf, Freemarker 등)을 사용하는 경우가 많습니다.

 

💡 MVC 패턴


 

📋 MVC

 

MVC는 "Model-View-Controller"의 약자로, 소프트웨어 디자인 패턴 중 하나입니다. 웹 애플리케이션을 개발하는 데 널리 사용되며, 사용자 인터페이스와 비즈니스 로직을 분리하여 유지보수성과 확장성을 향상시키는 데 도움이 됩니다.

하나의 서블릿이나 JSP만으로 비즈니스 로직과 뷰 렌더링을 함께 처리하게 되면 너무 많은 역할을 가지고 있고, 유지보수가 어려워집니다.
비즈니스 로직을 호출하는 부분에 변경이 발생해도 해당 코드를 수정해야하고, UI를 변경할 일이 있어도 비즈니스 로직이 있는 파일을 수정해야 하는 번거로움이 발생합니다.

UI와 비즈니스로직의 변경의 라이프 사이클이 다르다는 점이 패턴으로 영역을 분리하게된 가장 큰 부분입니다. JSP 같은 뷰 템플릿은 화면을 렌더링하는 데 최적화 되어있기 때문에 해당 업무만 담당하는 것이 장 효과적입니다.

컨트롤러 : HTTP 요청을 받아서 파라미터를 검증하고, 비즈니스 로직을 실행합니다. 그리고 뷰에 전달할 결과 데이터를 조회해서 모델에 담습니다.

모델 : 뷰에 출력할 데이터를 담아둡니다. 뷰가 필요한 데이터를 모두 모델에 담아서 전달해주는 덕분에 뷰는 비즈니스 로직이나 데이터 접근을 몰라도 되고, 화면을 렌더링 하는 일에 집중할 수 있습니다.

         - ModelHttpServletRequest 객체를 사용한다. request는 내부에 데이터 저장소를 가지고 있는데,               
            request.setAttribute() , request.getAttribute() 를 사용하면 데이터를 보관하고, 조회할 수 있다.

뷰 : 모델에 담겨있는 데이터를 사용해서 화면을 그리는 일에 집중합니다 . 여기서는 HTML을 생성하는 부분입니다.

 


 

MVC 중 Controller 역할을 하는 class

        package hello.servlet.web.servletmvc;

        ★ 컨트롤러의 역할 
        @WebServlet(name="mvcMemberFormServlet", urlPatterns = "/servlet-mvc/members/new-form")
        public class MvcMemberFormServlet extends HttpServlet {

            //mvc 패턴은 컨트롤러를 거쳐 뷰로 전달되기 때문에, memberForm을 보여주고 싶으려면 controller로 요청이 들어와야 함
            @Override
            protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

                String viewPath = "/WEB-INF/views/new-form.jsp"; //해당 jsp 파일로 이동하는 경로를 viewPath로 만들어줌
                RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);//컨트롤러에서 뷰로 이동할때 해당 경로로 이동할 수 있도록 해줌
                dispatcher.forward(request, response); // 다른 서블릿이나 JSP로 이동할 수 있는 기능 , 서버 내부에서 다시 호출이 발생
                                   // -> 리다이렉트로 이동하는 것이 아니라 서블릿 호출 -> jsp 호출 -> jsp에서 응답 만든 후 클라이언트에게 전송
            }
        }

         1. 고객의 요청이 오면 service 메서드가 호출된 후 viewPath의 jsp 경로를 호출함
         2. dispatcher.forward(request, response)로 서버 내부의 경로로 다시 호출
         3. new-form.jsp로 이동한 후 패당 view가 클라이언트에게 전달되어 보여

리다이렉트는 실제 클라이언트(웹 브라우저)에 응답이 나갔다가, 클라이언트가 redirect 경로로 다시 요청합니다. 따라서 클라이언트가 인지할 수 있고, URL 경로도 실제로 변경되는 반면에 포워드는 서버 내부에서 일어나는 호출이기 때문에 클라이언트가 전혀 인지하지 못합니다.

 


View 역할을 하게 될 jsp

        <%@ page contentType="text/html;charset=UTF-8" language="java" %>
        <html>

        <head>
            <meta charset="UTF-8">
            <title>Title</title>
        </head>
        <body>
        <!-- 상대경로 사용, [현재 URL이 속한 계층 경로 + /save] -->
        <form action="save" method="post">
            username: <input type="text" name="username" />
            age: <input type="text" name="age" />
            <button type="submit">전송</button>

        </form>
        </body>
        </html

        WEB-INF내부에 있는 파일들은 외부에서 직접적으로 불러와지는 것이 아니라
        무조건 컨트롤러를 통해서 뷰가 호출될 수 있도록 설정할 수 있음 (WEB-INF 안에 넣어두면 됨!)
        ex)localhost:8080/WEB-INF/views/new-form.jsp url을 작성한다고 해도 호출되지 않음

 

💥 mvc 패턴의 한계점


1. 복잡성 : MVC 패턴은 애플리케이션을 세 가지 기능으로 분리하므로 각각의 역할을 확실하게 정의하고 구현해야 합니다. 이로 인해 프로젝트가 커질수록 컨트롤러, 뷰, 모델 간의 관계가 복잡해질 수 있습니다.

2. 과도한 중재자 역할: 컨트롤러가 모든 요청을 중재하고 전달하므로 컨트롤러가 애플리케이션 내에서 중재자 역할을 맡게 됩니다. 이로 인해 컨트롤러가 비대해지고 유지보수가 어려워질 수 있습니다.

3. 높은 결합도: MVC 패턴은 각 기능을 분리하지만 여전히 서로 간에 의존성이 존재합니다. 이로 인해 하나의 기능을 변경할 때 다른 기능에도 영향을 미칠 수 있습니다.

4. 코드 중복: 여러 컨트롤러가 비슷한 기능을 구현해야 할 경우, 코드 중복이 발생할 수 있습니다. 이로 인해 유지보수가 어려워질 수 있습니다. View로 이동하는 코드가 항상 중복 호출되고,  viewPath도 중복하여 작성되고 있습니다.

5. 테스트의 어려움 : 컨트롤러는 외부 요청을 처리하므로 단위 테스트가 어려울 수 있습니다. 특히, 컨트롤러가 다른 컴포넌트와 강하게 결합되어 있을 경우 테스트하기 어려울 수 있습니다. 테스트 코드 작성 시 HttpServletRequest , HttpServletResponse를 사용하는 코드는 테스트 케이스를 작성하기 어렵습니다.

6. 공통부분 처리 어려움 : 단순하게 공통 기능을 하나의 메서드로 생성하면 될 것 같지만, 결과적으로는 해당 메서드를 항상 호출해야하고, 실수로 호출하지 않으면 문제가되고 해당 메서드를 반복해서 호출하는 것 또한 중복으로 호출이 됩니다.

해당 문제점을 해결하기 위해 컨트롤러 호출 전에 먼저 공통 기능을 처리하는 프론트 컨트롤러(Front Controller) 패턴을 도입하여 해당 문제를 해결할 수 있습니다.


💡 MVC 프레임 워크 만들기

 

프론트 컨트롤러 패턴이란 ❓

프론트 컨트롤러 패턴웹 애플리케이션의 디자인 패턴 중 하나로, 클라이언트의 모든 요청을 하나의 컨트롤러로 집중시켜 처리하는 패턴입니다.
프론트 컨트롤러도 하나의 서블릿이며, 이 서블릿 하나로 클라이언트의 요청을 받아서 해당 요청에 대한 처리를 담당하는 컨트롤러로서의 역할을 수행합니다. 프론트 컨트롤러를 제외한 나머지 컨트롤러는 서블릿을 사용하지 않아도 됩니다.

일반적으로 웹 애플리케이션은 여러 개의 컨트롤러로 이루어져 있으며, 각 컨트롤러는 특정한 요청을 처리하는 역할을 합니다. 하지만 프론트 컨트롤러 패턴에서는 클라이언트의 모든 요청이 먼저 프론트 컨트롤러로 집중되고, 프론트 컨트롤러가 각 요청에 맞는 적절한 컨트롤러를 호출하여 요청을 처리합니다.

프론트 컨트롤러의 특징

  1. 중앙 집중화 : 모든 클라이언트 요청을 하나의 프론트 컨트롤러로 집중시킴으로써 애플리케이션의 구조를 단순화합니다. 이로 인해 각 컨트롤러가 클라이언트 요청을 직접 처리하는 것이 아니라 프론트 컨트롤러를 통해 처리됩니다.

  2. 공통 로직 처리 : 프론트 컨트롤러에서는 모든 요청에 공통적으로 필요한 로직을 처리할 수 있습니다. 예를 들어, 로그인 여부 확인, 권한 검사, 국제화 등의 작업을 한 곳에서 처리할 수 있습니다.

  3. 중복 코드 제거 : 프론트 컨트롤러에서 공통 로직을 처리하므로 다른 컨트롤러에서 해당 로직을 중복해서 작성할 필요가 없어집니다. 이로 인해 코드의 중복성을 줄이고 유지보수가 용이해집니다.

  4. 유연한 확장성 : 새로운 기능이나 요청이 추가되더라도 프론트 컨트롤러만 수정하면 됩니다. 기존의 컨트롤러를 수정할 필요가 없기 때문에 애플리케이션의 확장성이 좋아집니다.

  5. 코드 재사용성 : 공통 로직을 프론트 컨트롤러에서 처리하므로 다른 컨트롤러에서도 해당 로직을 재사용할 수 있습니다.

  6. 유지보수 용이성 : 프론트 컨트롤러 패턴을 사용하면 모든 요청이 한 곳에서 처리되기 때문에 유지보수가 용이해집니다. 추가 기능의 변경이나 버그 수정 등을 프론트 컨트롤러에서 처리하면 다른 컨트롤러의 코드를 건드릴 필요가 없습니다.

프론트 컨트롤러 패턴은 웹 애플리케이션의 구조를 더욱 효율적이고 유연하게 만들어주며, 중복 코드를 줄이고 보안을 강화하는 데에 도움이 됩니다. 스프링 웹 MVC의 DispatcherServlet이 FrontController 패턴으로 구현되어 있습니다.

 

728x90
반응형

'[ BACKEND] > Spring' 카테고리의 다른 글

[SPRING] 값 타입 컬렉션  (0) 2023.08.21
[SPRING] 기본 값 타입  (0) 2023.08.20
[SPRING] 영속성 전이 & 고아객체  (0) 2023.08.19
[SPRING] 즉시 로딩과 지연 로딩  (0) 2023.08.18
[SPRING] ✅ Proxy  (0) 2023.08.17

+ Recent posts