실제로 각 페이지별로 html 파일이 따로 존재하며 페이지를 이동하게 될 경우 브라우저에서는 해당 페이지의 html파일을 받아와서 화면에 표시해준다!!

근데 페이지가 수많아지면 어떻게 관리를 해야하지?

이런 문제를 해결하기 위하여 나온 것이 바로 SPA(single page application)임.

이건 말그대로 하나의 페이지만 존재하는 웹 또는 어플리케이션임. 페이지가 여러개면 MPA 하나면 SPA (처음에는 이 HTML파일의 바디태그 내부가 텅 비어있다가 해당 페이지에 접속할때 그 페이지에 해당하는 콘텐츠를 가져와서 동적으로 BODY태그 내부를 채워넣게됨.

 

자바스트립트의 함수

함수는 입력을 받아서 정해진 출력을 하는 것

여기서 함수의 입력을 파라미터 또는 인자라고함

자바스크립에서 함수를 정의하는 방법은 두가지인데 첫번째는 FUNCTION SATEMENT이고 두번째는 ARROW FUNCTION EXPRESSION을 사용하는 방법임.

 

FUNCTION STATEMENT를 사용하였을때

function sum(a,b) {
	return a+b;
}

 

ARROW FUNCTION EXPRESSION을 사용하였을때

const multiply = (a,b) => {
	return a*b;
}

 

리액트는 자바스크립트 라이브러리임 라이브러리는 자주 사용되는 기능을 정리해 모아 놓은 것

그럼 사용자 인터페이스를 만들기 위한다는것은 무슨 의미일까 

사용자 인터페이스는 UI라고 하는데 이건 사용자와 컴퓨터 프로그램이 서로 상호작용을 하기 위해 중간에서 서로간에 입력과 출력을 제어해주는 것이 바로 UI임.

걍 우리가 보는 버튼이나 텍스트 입력창같은거임. 히히

리액트는 대표적인 자바스크립트 UI 라이브러리임.

 

뭐 정리하자면 리액트는 사용자와 웹사이트의 상호작용을 돕는 인터페이스를 만들기 위한 자바스크립트 기능 모음집 정도!

 

리액트는 빠른 업데이트를 위해 내부적으로 Virtual DOM이라는 것을 사용함.

쉽게 설명해보자면 Virtual DOM은 말 그대로 가상의 DOM임. DOM은 DOCUMENT OBJECT MODEL의 약자로 웹페이지를 정의하는 하나의 객체라고 생각하면됨. 

쉽게말해서 하나의 웹사이트에 대한 정보를 모두 담고 있는 큰 그릇이라고 보면됨.

 

기존의 방식으로 화면을 업데이트 하려면 DOM을 직접 수정해야하는데 이것은 성능에 영향을 크게 미치고 비용도 굉장히 많이듬. (수정할 부분을 DOM의 데이터에서 모두 찾아야 하기 때문)

하지만 리액트는 DOM을 직접 수정하는 것이 아니라 업데이트해야할 최소한의 부분을 검색하고 검색된 부분만을 업데이트하고 다시 렌더링하면서 변경된 내용을 빠르게 사용자들에게 보여줌.

 

컴포넌트는 구성요소라는 뜻. 리액트는 모든 페이지가 컴포넌트로 구성되어있고, 하나의 컴포넌트는 또 다른 여러개의 컴포넌트의 조합으로 구성될 수 있음. 따라서 리액트로 개발을 하다보면 레고블록을 조립하는 것처럼 컴포넌트를 조합해서 웹사이트를 개발하게됨. 

 

재사용성! 객체지향프로그래밍에서 등장하는데 소프트웨어 개발에 있어서 매우 중요함. 이건 다시 사용이 가능한 성질인데 이 재사용성은 의존성 문제말고도 여러가지 호환성 문제도 발생할수있음 따라서 재사용성이 높게 개발하는것이 좋음

다시 말하자면 다른 모듈에 의존성을 낮추고 호환성 문제가 발생하지 않도록 개발해야한다!!

 

이러한 재사용성이 높아지면 개발 기간이 단축됨. 기존에 개발해둔 모듈을 곧바로 재사용하여 개발하면 되기때문에 개발기간을 많이 줄일수있음. 

또한 유지보수가 용이함. 소프트웨어에서 공통으로 사용하는 모듈에 문제가 생기면 해당 모듈만 수정해서 다시 배포하면되기때문!

이렇게 재사용성이 높게 개발을 하면 버그를 찾기에도 훨씬 수월함. 재사용성이 높다? -> 모듈간의 의존성이 낮다

따라서 리액트 컴포넌트를 개발할때 항상 쉽고 재사용 가능한 형태로 개발하는 것이 중요함.

 

근데 리액트는 높은 상태 관리 복잡도를 가지고있음. state라는 개념이 있는데 쉽게말해 리액트 컴포넌트의 상태를 의미함. virtual dom은 바뀐 부분만을 찾아서 업데이트한다고 했는데 바뀐 부분이라는 것은 state가 바뀐 컴포넌트를 의미함. 따라서 state는 리액트에서 중요한 부분임.

성능 최적화를 위해 state를 잘관리하는 것이 중요함. 

따라서 상태관리를 할땐 redux등의 외부 상태관리 라이브러리를 사용하는 경우가 많음. ㅈㄴ어렵다는 소리 ㅠㅠ

 

 

jsx는 자바스크립트 확장 문법임. jsx언어는 자바스크립트와 연관이 있으며, 자바스크립트의 문법을 확장시킨것.

jsx = 자바스크립트 + XML/HTML임.

대충 보자면

const element = <h1>Hello world</h1>;

이렇게 자바스크립트와 html코드가 결합되어있음.

이 위에 코드가 하는 역할은 element라는 변수에 h1태그로 둘러싸인 문자열을 저장하는것.

 

jsx는 내부적으로 html코드를 자바스크립트로 변환하는 과정을 거치게됨. 그래서 jsx코드를 작성해서 최종적으로는 자바스크립트 코드가 나오게 되는것.

이때 jsx코드를 자바스크립트 코드로 변환하는 역할을 하는 것이 바로 리액트의 createElement()라는 함수.

 

대충 예시를 들어보자면 

class Hello extend React.Component {
	render() {
    	return <div>Hello {this.props.toWhat}</div>
       }
 }
 
 ReactDOM.render(
 	<Hello toWhat="World" />
    document.getElementById('root')
 );

이건 Hello 라는 리액트 컴포넌트인데 jsx를 사용하고 있는걸 볼 수 있다.

그리고 ReactDOM의 render을 사용하여서 실제 화면에 렌더링하고있다.

 

class Hello extends React.Component {
	render() {
    	return React.createElement('div' , null, `Hello ${this.props.toWhat}`);
     }
}

ReactDOM.render(
	React.createElement(Hello, { toWhat: 'World' }, null),
    document.getElementById('root')
);

이 코드는 jsx를 사용하지않은 순수한 자바스크립트로만 작성된 코드이다 하지만 위코드와 아까 코드는 동일한 역할을 수행함.

jsx를 사용했던 부분이 React.createElement()라는 함수로 대체된걸 볼 수 있음!

---> jsx문법을 사용하면 리액트에서는 내부적으로 createElement()라는 함수로 사용하도록 변환됨.

 

그렇다면!! createElement()함수의 파라미터로는 어떤것이 들어가는지 자세히 살펴보자!!

React.createElement(
	type,
    [props],
    [...children]
)

왜 줄이 안맞지...흠...암튼

첫번째 파라미터로는 엘리먼트의 유형을 나타냄(type) 이 유형으로는 div나 span같은것들, 다른 리액트 컴포넌트같은 것들 있잖아 그런것들이 올 수 있음.

두번째 파라미터로는 props가 들어가게됨. 

세번째로는 children이 들어가게되는데 이 children이란 현재 엘리먼트가 포함하고 있는 자식 엘리먼트.

props란 개념은 추후에 다룰것임! 겁나게 어렵기 때문!

 

이렇게 jsx를 사용하면 createElement를 사용했을때보다 좀 더 간결하고 가독성이 올라가기에 jsx를 사용하는 것을 추천.

그리고 jsx를 사용하면 injection Attack이라 불리는 해킹을 방어할 수 있어서 보안성이 올라감.

const title = response.potentiallyMaliciousInput
const element = <h1>{title}</h1>
//이 코드는 안전함

이렇게 title이라는 변수에 잠재적으로 보안 위험의 가능성이 있는 코드가 삽입되었지만 jsx코드에서는 괄호를 사용하여 title변수를 삽입하고있음.

-> ReactDOM은 렌더링 하기 전에 임베딩(삽입)된 값을 모두 문자열로 변환하여서 명시적으로 선언되지 않은 값은 괄호 사이에 들어갈수없음( 만약 입력창에 문자나 숫자같은 일반적인 입력값이 아닌 소스코드를 입력하여서 해당 코드가 실행이되어버리면 해킹이 될수 있으나 이러한 특징이있어 방어가능)

결과적으로XSS라 불리는 cross-site-scripting attacks방어가능

그냥 좀 뭔가 심심하기도하고 그래서 딴소리좀 했움 ㅎㅎ...

 

jsx를 사용할땐 그냥 html과 자바스크립트가 섞인 형태로 코드를 작성해주면됨.

function formatName(user) {
	return user.firstName + ' ' + user.lastName;
 }
 
 const user = {
 	firstName: 'taeyoung',
    lastName: 'kim'
};

const element = (
	<h1>Hello, {formatName(user)}</h1>
);

ReactDOM.render(
	element,
    document.getElementById('root')
);

이렇게 html 코드 사이에 괄호를 사용해서 변수가 아닌 formatName(user)라는 자바스크립트 함수를 호출.

 

만약 사용자의 이름에 따른 인사말을 표현하고 싶다면?

function greeting(user) {
	if (user) {
    	return <h1> Hello, {formatName(user)}!</h1>
     }
     return <h1>Hi stranger</h1>
}

 

그럼 children을 정의하고싶다면?

그냥 하위태그를 상위태그로 감싼다고 생각하면됨.

const element = (
	<div>
      <h1>안녕</h1>
      <h2>리액트 공부하쟈</h2>
    </div>
 );

이렇게 하면 div태그의 children은 h1과 h2가 됨.

 

 

엘리먼트는 리액트 앱을 구성하는 요소를 의미함. 리액트 공식 홈페이지에서는 엘리먼트는 리액트 앱의 가장 작은 빌딩 블록들이라고 정의하고있음.

엘리먼트는 원래 웹사이트에 대한 모든 정보를 담고있는 객체인 DOM에서 사용하는 용어임.

하지만 DOM엘리먼트와는 다르게 리액트 엘리먼트가 따로있음.

DOM엘리먼트는 웹에서 개발자도구 켜서 나오는것들.

실제 브라우저의 DOM에 존재하는 엘리먼트는 DOM엘리먼트가 되는 것이고 리액트의 Virtual DOM에 존재하는 엘리먼트가 리액트 엘리먼트가 되는것임

즉, 리액트 엘리먼트는 DOM 엘리먼트의 가상 표현

엘리먼트는 컴포넌트 유형 과 속성 및 내부의 모든 자식에 대한 정보를 포함하고있는 일반적인 자바스크립트 객체.

 

이러한 엘리먼트는 불변성이라는 특징을 가지고있는데 엘리먼트는 한번 생성이되면 바꿀수 없기때문에 엘리먼트를 업데이트 하기 위해서는 다시 생성해야한다.

function tick() {
	const element = (
    	<div>
        	<h1>안녕 리액트!</h1>
            <h2> 현재 시간: {new Date().toLocaleTimeString()}</h2>
         </div>
     );
     
     ReactDOM.render(element, document.getElementById('root'));
    
 }
 setInterval(tick, 1000);

이 tick이라는 함수를 정의하고있는 코드는 현재 시간을 포함하고 있는 엘리먼트를 생성하여 root div에 렌더링하는 역할을 함. 

또한 자바스크립트의 setInterval()함수를 사용하여서 tick()함수를 1초에 한번씩 호출하고있음. 

이 코드의 실행결과는 매초 화면에 새로운 시간이 나오는데 이것은 tick함수가 호출될때마다 기존 엘리먼트를 변경하는것이 아니라, 새로운 엘리먼트를 생성하여 바꿔치기 하는것임.

 

근데 여기서 실제로 현재 시간을 초단위로 띄우는 걸 웹으로 표현할때 

 

이렇게 toLocaleTimeString()함수를 사용하여서 실제 시간을 받아온후에 그냥 index.js에 컴포넌트를 가져와서 화면에 나타내기만 하면 되는게 아니라 index에서도 추가작업이 필요함.

초당 새로 업데이트 되는 걸 표현해주기 위하여 

이렇게 setInterval함수를 사용하여서 매초마다 주기적으로 업데이트가 진행이 될수있도록 해주어야함.

 

리액트는 컴포넌트 기반의 구조임!

모든 페이지가 컴포넌트로 구성되어있고 하나의 컴포넌트는 또 다른 여러개의 컴포넌트의 조합으로 구성

이렇게 컴포넌트를 반복적으로 사용함으로써 전체 코드의 양이 줄어 자연스레 개발시간과 유지보수 비용도 줄일수있음.

 

이러한 리액트 컴포넌트에서의 입력은 props라는 것이고 출력은 앞에서 배운 리액트 엘리먼트가됨

결국 리액트 컴포넌트가 해주는 역할은 어떠한 속성들을 입력으로 받아서 그에 맞는 리액트 엘리먼트를 생성하여 리턴해주는것.

쉽게 말하자면 리액트 컴포넌트는 만들고자하는대로 props(속성)을 넣으면 해당 속성에 맞춰 화면에 나타날 엘리먼트를 만들어주는 것.

더 쉽게말하자면 붕어빵 틀 같은것임 여기서 붕어빵 틀은 컴포넌트, 각 붕어빵들은 엘리먼트

객체지향의 개념에서 나오는 클래스와 인스턴스의 개념과 비슷.

 

props는 리액트 컴포넌트의 속성임. 붕어빵을 만들때 컴포넌트라는 붕어빵 틀에 어떤 props를 넣는지에 따라 각기 다른 엘리먼트들이 나오는것임.

이처럼 props는 리액트 컴포넌트에서 눈에보이는 글자나 색 등의 속성을 바꾸고 싶을때 사용하는 컴포넌트속의 재료.

props는 컴포넌트에 전달할 다양한 정보를 담고 있는 자바스크립트 객체

이러한 props를 통하여 컴포넌트를 통해 엘리먼트를 생성하면 이 생성된 엘리먼트에 대해서는 더이상 props값을 변경할수가없음. 따라서 다른 props값을 넣어주고싶다면 다시 컴포넌트에 값을 넣어서 새로운 엘리먼트를 만들어주면댐.

 

우리가 함수를 구분지을때에는 pure함수와 impure함수로 구분을 하는데 이때 

pure함수에 대해서 먼저 설명을 해보자면 

function sum(a, b) {
	return a+b;
}

이러한 간단한 함수를 예시로 들어보자면 a와b라는 파라미터의 값을 받아서 그 둘의 합을 리턴할때 a,b라는 파라미터의 값을 변경하지않고있음 -> 이경우가 pure하다.

 

impure함수를 보면

function withdraw(account, amount) {
	account.total -= amount;
}

이 함수를 보자면 account와 amount라는 파라미터를 받아서 account의 total이라는 값에서 amount라는 값을 빼는 함수임 쉽게 말하자면 은행 계좌에서 출금을 하는 함수. 이 경우를 보면 입력으로 받은 파라미터인 account의 값을 변경했으므로 impure한것임.

 

왜 이얘기를 했냐하면

리액트 공문에 모든 리액트 컴포넌트는 그들의 props에 관해서는 pure 함수 같은 역할을 해야함.

더 쉽게말하자면 리액트 컴포넌트는 props를 직접 바꿀순없고 같은 props에 관해서는 항상 같은 결과를 보여줄것!

 

jsx를 사용하면 키-값 쌍의 형태로 컴포넌트에 props를 넣을수있음

function App(props) {
	return (
    	<Profile
        	name="태영"
            introduction="안녕 난 태영이야"
            viewCount={1500}
         />
       );
 }

띄어쓰기 자꾸 왜이러는데...

App 컴포넌트가 나오는데 이 안에서 profile컴포넌트를 사용하고있음

이 profile컴포넌트 안에 name, introduction, viewCount라는 세가지 속성이 있는데 이 속성의 값이 모두 profile컴포넌트에 props로 전달되며, props는 아래와 같은 형태의 자바스크립트 객체가됨.

{
	name:"태영",
    introduction: "안녕 난 태영이야",
    viewCount: 1500
}

 주의할점은 props에 값을 넣을때에 문자열 이외에 정수, 변수, 그리고 다른 컴포넌트등이 들어갈 경우에는 중괄호를 사용하여서 감싸주어야함.

 

중괄호를 사용하는 예시를 들어보자면

funtion App(props) {
	return (
    	<Layout
        	width={2560}
            height={1440}
            header={
            	<Header title="태영의 블로그" />
             }
             footer={
             	<Footer />
             }
          />
       );
  }

 

컴포넌트는 함수 컴포넌트와 클래스 컴포넌트가 있음.

 

컴포넌트의 이름을 지을땐 항상 대문자로 시작.

소문자로 시작하면 DOM태그로 인식하기때문임.

 

이러한 컴포넌트들을 당연히 합성을 해서 만들수도있음.

function Welcome(props) {
	return <h1>Hello, {props.name}</h1>
 }
 
 function App(props) {
 	return (
    	<div>
        	<Welcome name="Mike" />
            <Welcome name="Steve" />
            <Welcome name="Jane" />
         </div>
      )
  }
  
  ReactDOM.render(
  	<App />
    document.getElementById('root')
);

이렇게 해버리면 App컴포넌트는 Welcome컴포넌트 세개를 포함하고있는 컴포넌트가됨.

 

반대로 복잡한 컴포넌트를 쪼개서 컴포넌트 추출을 할수도있음.

이걸 잘하면 컴포넌트의 재사용성이 올라감.

 

자자 가보자~

function Commnet(props) {
	return (
    	<div className="comment">
        	<div className="user-info">
            	<img className="avatar">
                	src={props.author.avatarUrl}
                    alt={props.author.name}
                  />
                  <div className="user-info-name">
                  	{props.author.name}
                  </div>
                </div>
                
                
                <div className="comment-text">
                	{props.text}
                 </div>
                 
                 
                 <div className="comment-data">
                 	{formatDate(props.date)}
                 </div>
             );
      }

여기에 이렇게 comment컴포넌트가 있는데 이건 내부에 작성자의 프로필 이미지,  이름, 댓글내용 ,작성일이 들어가있음.

이 컴포넌트에서 하나씩 컴포넌트들을 추출해보자.

 

우선 avatar컴포넌트 추출임.

comment 컴포넌트에서는 이미지태그를 사용하여서 사용자의 프로필 이미지를 표시하고 있음. 이부분을 추출할거임

 

function Avatar(props) {
	return (
    	<img className="avatar"
        	src={props.user.avartarUrl}
            alt={props.user.name}
          />
       );
  }

props에 기존에 있던 author보다 좀 더 보편적인 user사용. 이렇게 보편적인것을 사용해야 재사용성이 올라가기때문.

이제 이 추출한 컴포넌트를 다시 위에있는 코드에 적용한다면?

 

function Commnet(props) {
	return (
    	<div className="comment">
        	<div className="user-info">
            	<Avatar user={props.author} />
                  <div className="user-info-name">
                  	{props.author.name}
                  </div>
                </div>
                
                
                <div className="comment-text">
                	{props.text}
                 </div>
                 
                 
                 <div className="comment-data">
                 	{formatDate(props.date)}
                 </div>
             );
      }

이렇게됨.

이제 다음으로는 사용자 정보를 담고있는 부분을 추출해보자.

 

function UserInfo(props) {
	return (
    	<div className="user-info">
        	<Avatar user={props.user}>
            <div className="user-info-name">
            	{props.user.name}
            </div>
        </div>
      );
  }

사용자 정보를 담고있는 부분을 추출할때 이렇게 avatar컴포넌트도 같이 안에 들어가있는걸 볼 수 있다.

역시 아까와 마찬가지로 좀 더 보편적인 의미를 담고있는 user을 props에 사용

 

그럼 이 추출한 UserInfo 컴포넌트도 원래의 comment컴포넌트에 대입을 해보자

function Commnet(props) {
	return (
    	<div className="comment">
        	<UserInfo user={props.author} />
            
                <div className="comment-text">
                	{props.text}
                 </div>
                 
                 
                 <div className="comment-data">
                 	{formatDate(props.date)}
                 </div>
             );
      }

전보다 훨씬 간단해진걸 볼 수 있다.

이러한 컴포넌트 추출을 함에 있어서 기능단위로구분하는것이 좋고, 나중에 곧바로 재사용이 가능한 형태로 추출하는것이 좋다.

 

이렇게 comment 컴포넌트를 만들었는데 comment의 작성자 이름과 댓글 내용을 동적으로 변경해주기 위하여 props를 사용함.

근데 이렇게 하고 npm run start를 하면 작성자 이름과 댓글 내용이 나오지 않는데 그 이유는 그냥 name이랑 comment값이 정의가 안되어있어서 그럼 css는 걍 알아서 먹임

 

이런식으로 컴포넌트에 props값을 전달해주면

이렇게 뜸.

 

그럼 이제 데이터를 별도의 객체로 분리해서 동적으로 받아온 데이터를 표시가되게 만들어보자

왜냐면 저런식으로하면 어떻게 데이터를 받아와서 일일이 다 저렇게해 ㅇㅈ?

 

이렇게 예시로 더미데이터를 만들어서 이걸 map함수에 적용해서 comments에 있는 데이터들을 받아와서 컴포넌트에 대입시켜서 출력해주면댐.

 

 

'REACT' 카테고리의 다른 글

Life cycle and hook  (0) 2023.07.14
Shared state  (0) 2023.07.13
REACT  (0) 2023.04.29
React  (0) 2022.11.09
useRef  (0) 2022.07.28

+ Recent posts