React 장인 되기 -1

donggae·2023년 10월 11일
1

React

목록 보기
1/8
post-thumbnail

🌐 React

리액트는 자바스크립트 라이브러리로 사용자 인터페이스를 만드는데 사용한다.
구조가 MVC, MVW 등인 프레임워크와 달리, 오직 V(View)만을 신경 쓰는 라이브러리이다.

1. 리액트를 공부하기 위해 작업 환경을 설정 해보자

Node.js가 설치 되었다는 전제로 시작한다.
저자는 npm을 통하여 설치를 진행한다.

  • npx create-react-app <프로젝트 이름>
  • npm create-react-app <프로젝트 이름>

두개의 명령어가 있는데 무엇이 다를까?

npmnpx
의미Node.js 패키지 매니저로 사용패키지를 실행하지만, 설치하지 않음
사용 목적패키지 설치 및 전역 명령 실행일회성 패키지 실행 및 설치 (전역 설치 X)
실행 방법npm install -g 패키지명npx 패키지명
패키지 버전패키지의 전역 설치 버전 사용항상 최신 버전을 사용
특징패키지 버전 관리가 가능, 여러 프로젝트에서 재사용 가능글로벌 설치 없이 필요한 패키지를 즉시 실행

설치가 완료 되었으면, 해당 폴더로 이동 cd 프로젝트 이름 -> npm start

오케이 시작이 반이라고 했으니 반정도 왔다.

2. React 프로젝트의 기본 폴더 구조를 파악해보자

2-1. Package.json

가장 먼저 package.json 파일에 대해 알아보자

Node.js 프로젝트의 구성 및 의존성 정보를 저장하는 .json 파일

  • 프로젝트 구성 정보 - 프로젝트의 이름, 버전, 설명 등이 포함
    name, version, private, ....
  • 의존성 목록(dependencies) - 해당 프로젝트를 실행,개발하는 데 필요한 모든 외부 라이브러리 및 모듈을 포함
  • 스크립트(scripts) - 해당 프로젝트를 빌드, 실행, 배포 하기 위한 명령어가 포함
    start, build, test, ....

스크립트 부분에서 start 부분이 react-scripts start인 것을 보아
npm start를 했을 때 리액트 프로젝트가 실행이 되는 것을 알 수 있다.

2-2. App.js, index.js 파일 파헤쳐보기

import React from 'react';

CSS에서 어떠한 파일을 불러와 사용하는 문법이랑 똑같이 생겼다.

위 코드는 내가 생각한 것 처럼 리앤트를 불러와 사용할 수 있게 해주는데
프로젝트 생성 과정에서 node_modules 폴더에 react 모듈이 설치 되고, 이를 통해
import문을 통하여 리액트를 불러와 사용할 수 있는 것이다.

import logo from './logo.svg';
import './App.css';

import 문을 사용하여 다른 파일에서 정의한 내용을 현재 파일로 불러와 사용할 수 있으며, 이를 통해 코드를 모듈화하고 다른 파일에서 정의한 내용을 현재 파일에서 재사용할 수 있다.

function App() {
  return (
    <div className="App">
    	...
    </div>
  )
};

App이라는 컴포넌트를 function 키워드를 사용하여 컴포넌트를 만들게 되는데
이를 함수형 컴포넌트라 부른다. 이러한 코드를 JSX라고 부르는데 JSX가 무엇인지 알아보자

3. What is JSX

JSX(JavaScript XML) 자바스크립트의 확장 문법으로, JS코드 내에서 HTML과 유사한 구문을 사용하여 UI 컴포넌트를 만들고 렌더링하는 데 도움을 준다.

function App() {
	return(
    	<div>
        	Hello! <b>React</b>
      	</div>
    )
};

이러한 코드는 다음과 같이 변환이 된다.

	function App() {
    	return React.createElement("div", null, "Hello!", React.createElement("b", null, "React"));
    }

JSX 문법을 사용하는 것이 아니라 항상 createElement를 쓰게 되면 불편할 것이다
그렇기에 JSX를 사용하면 편하게 렌더링을 할 수 있다.

3-1. JSX의 문법

JSX를 올바르게 사용하기 위해 규칙에 대하여 알아보자

1. 여러 요소를 감싸는 부모 요소가 반드시 하나가 필요하다.

import React from 'react';

function App () {
  return (
    <h1>리액트의 JSX 문법 공부</h1>
    <p>1. 감싸인 요소를 꼭 포함한다.</p>
  )
}

export default App;

이렇게 되게 되면 제대로 작동하지 않을 것이다.

"JSX 식에는 부모 요소가 하나 있어야 합니다" 라고 에러가 발생하는 것을 볼 수 있다.
위의 식을 에러 없이 제대로 작동하게끔 코드를 수정해보자

  1. div 태그 사용하기
import React from 'react';

function App () {
  return (
    <div>
      <h1>리액트의 JSX 문법 공부</h1>
      <p>1. div 태그로 감싸기</p>
    </div>
  )
}

export default App;
  1. Fragment 태그 사용하기
import React from 'react';

function App () {
  return (
    <React.Fragment>
      <h1>리액트의 JSX 문법 공부</h1>
      <p>2. 최상위 요소를 두기 싫을 때 Fragment 사용하기</p>
    </React.Fragment>
  )
}

export default App;
  1. 빈 태그 사용하기
import React from 'react';

function App () {
  return (
    <>
      <h1>리액트의 JSX 문법 공부</h1>
      <p>3. 빈 태그 사용하기</p>
    </>
  )
}

export default App;

2. 자바스크립트 표현식을 사용하는 방법

jsx내부에서 js 표현식 사용하기

import React from 'react';

function App () {
  const name = "리액트";
  return (
    <div>
		<h1>{name}JSX 문법 공부</h1>
	</div>
  )
}

export default App;

{}를 사용하여 jsx 내부에서 렌더링 하기

3. if 문 대신 조건부 연산자를 사용하자

JSX 내부의 자바스크립트 표현식에서 if문을 사용 할 수 없다.

import React from 'react';

function App() {
	const name = '리액트';
	return <div>{name === '리액트' ? <h1>리액트 입니다.</h1> : <h1>리액트가 아닙니다</h1>}</div>;
}

export default App;

JSX내부에선 삼항 연산자를 사용하자

4. AND 연산자(&&)를 사용한 조건부 연산자

아무것도 렌더링을 하고 싶지 않을 때 AND연산자를 사용하자

위의 3번에서 배운 조건부 연산자를 사용하여 null값을 사용하여 아무것도 렌더링 하지 않을 수 있지만
AND 연산자(&&)를 사용하면 더 간결하게 사용할 수 있다.

import React from 'react';

function App() {
	const name = '리액트';
	return <div>{name === '리액트' && <h1>리액트 입니다.</h1>}</div>;
}

export default App;

name이 "리액트"일 경우 화면에 표시가 되지만 아닐 경우 아무것도 표시가 되지 않는걸 볼 수 있다.

5. 인라인 스타일링

카멜표기법으로 작성하자

import React from 'react';
function App() {
	const name = '리액트';
	const style = {
		backgroundColor: 'black',
		fontSize: '50px',
		textAlign: 'center',
		color: 'aqua',
	};
	return <div style={style}>{name}</div>;
}

export default App;
  • 위와 같이 스타일을 적용할 때에는 문자열이 아닌 객체 형태로 넣어준다.
  • background-color가 아닌 backgroundColor와 같이 카멜 표기법을 사용한다.

6. 태그는 꼭 닫아야 한다.

import React from 'react';

function App() {
	return (
		<div>
			<h2>리액트를 배워보자</h2>
			<input>
		</div>
	);
}

export default App;

해당 코드는 Parsing error : Unterminated JSX contents
즉 모든 태그는 닫는 태그를 사용해야한다.

<input />, <br /> ....

7. 주석을 사용할 때 이렇게 사용하자

JS나 HTML에서 사용하는 주석을 사용하게 되면 화면에 표시되게 된다
그렇기에 {/* ... */}의 형태로 사용하자!

import React from 'react';
function App() {
	return (
		<>
			<h1>리액트의 JSX 문법 공부</h1>
      		{/* 주석은 이렇게 사용합니다 */}
      		// 이렇게 사용하면 화면에 보여지게 됩니다.
      		/* 이렇게 사용해도 화면에 보여지게 됩니다.*/
		</>
	);
}

export default App;

4. State(상태)

컴포넌트 내부에서 바뀔 수 있는 값

React에서 사용하는 State를 알아보기 위해 기본적으로 버튼을 눌렀을 때
1씩 증가, 1씩 감소 그 값을 화면에 렌더링 하는것을 구현해보자

  1. 먼저 리액트의 State를 사용하기 위해서는 React를 import 하고
    상태변화에 사용되는 useState를 추가적으로 적어야 한다.
import React, { useState } from 'react';

Returns a stateful value, and a function to update it
-> "현재 상태 값을 나타내는 변수 + 상태 값을 업데이트하는 함수를 반환한다" 라고 알려준다.

  1. useState를 사용하여 상태 값을 초기화, 업데이트 함수를 선언
const [count, setCount] = useState(0);

배열의 비구조화 할당을 이용하여 다음과 같은 값을 가지게 한다.
count - 상태 값
setCount - 상태 값을 업데이트하는 함수

  1. 상태 값을 업데이트 하는 함수를 만들기
const onIncrease = () => {
	setCount(count + 1);
};
const onDecrease = () => {
	setCount(count - 1);
};

증가,감소 함수를 사용하여 현재 상태 값인 count를 +1, -1씩 하는 함수를 만들어 봤다.

  1. 전체 코드를 작성해보자
import React, { useState } from 'react';

const Counter = () => {
  const [count, setCount] = useState(0);

  const onIncrease = () => {
    setCount(count + 1);
  };
  const onDecrease = () => {
    setCount(count - 1);
  };

  return (
    <div>
      <h2>{count}</h2>
      <button onClick={onIncrease}>증가 버튼</button>
      <button onClick={onDecrease}>감소 버튼</button>
    </div>
  );
};

처음 보는 문법이라 아직 익숙하진 않은데 확실한건 js로만 했을 때보다는 더 간결하다는 점

  • useState(0) - 초기 값 0 그렇기에 count가 0으로 출력 되는 걸 볼 수 있다.

5. Prop(Properties)

컴포넌트에 데이터 전달하기

부모 컴포넌트인 App.js 파일이 있고 자식 컴포넌트인 Counter.js가 있다
위에서 버튼을 눌렀을 때 증감이 되는 함수가 포함된 파일 즉 자식 컴포넌트가 Counter.js

5-1. 부모 컴포넌트에서 데이터 내려주기

App.js

import React from 'react';
import Counter from './Counter';

function App() {
	return(
    	<>
        	<Counter initialNumber={5}/>
        </>
    ) 
}

5-2. 자식 컴포넌트에서 데이터 받기

Counter.js

import React, { useState } from 'react';

const Counter = (props) => {
  console.log(props);
  const [count, setCount] = useState(0);

  const onIncrease = () => {
    setCount(count + 1);
  };
  const onDecrease = () => {
    setCount(count - 1);
  };

  return (
    <div>
      <h2>{count}</h2>
      <button onClick={onIncrease}>증가 버튼</button>
      <button onClick={onDecrease}>감소 버튼</button>
    </div>
  );
};

export default Counter;

부모 컴포넌트에서 데이터를 적기만 한다고 자식 컴포넌트에 전달이 되는것이 아닌
데이터를 받고자 하는 자식 컴포넌트에서 props를 매개변수로 받는다.
이를 console.log에 찍어보면 object 즉 객체로 받는것을 볼 수 있다.

그럼 받은 데이터를 사용해보자

편의를 위해 코드를 생략하고 작성하겠다

// App.js
function App() {
  return (
    <>
      <Counter initialNumber={5} />
    </>
  );
}


// Counter.js
const Counter = (props) => {
  const [count, setCount] = useState(props.initialNumber); // 화면에 초기 값이 5로 경 된 것을 볼 수 있다.
};

props가 console 창에서 객체로 나오기에 그 값에 접근 하기 위해서 props.키값
으로 접근을 하였고 화면에 받은 데이터

주고자 하는 데이터가 많을 경우 스프레드 연산자를 활용하자

// App.js

function App() {
  const counterProps = {
    a: 1,
    b: 2,
    c: 3,
    d: 4,
    f: 5,
  };

  return (
    <>
      <Counter {...counterProps} />
    </>
  );
}

넘겨주고자 하는 데이터가 많을 경우 태그 안에 나열 보다는 새로운 객체를 생성해서
스프레드 연산자로 받는것을 지향하자

넘겨준 값을 정의 하지 않은 경우 초기 설정 값을 해두자

// App.js

import React from 'react';
import Counter from './Counter';

function App() {
  const counterProps = {
    a: 1,
    b: 2,
    c: 3,
    d: 4,
    f: 5,
  };
  return (
    <>
      <Counter {...counterProps} />
    </>
  );
}

export default App;


// Counter.js

import React, { useState } from 'react';

const Counter = (props) => {
  const [count, setCount] = useState(props.initialNumber);

  const onIncrease = () => {
    setCount(count + 1);
  };
  const onDecrease = () => {
    setCount(count - 1);
  };

  return (
    <div>
      <h2>{count}</h2>
      <button onClick={onIncrease}>증가 버튼</button>
      <button onClick={onDecrease}>감소 버튼</button>
    </div>
  );
};

export default Counter;

이렇게 되면 initialNumberundefined가 되기에 여기에 연산을 하게 되면 NaN이 렌더링 된다.
이는 오류이기에 해당 코드를 초기 설정값을 통해 이러한 문제를 해결해보자

Counter.defaultProps = {
  initialNumber: 0,
};

App.js에 해당 코드를 넣음으로써 NaN이 렌더링 되는것을 방지할 수 있다.

또한 신기한 사실은 부모 컴포넌트의 State의 변경에 따른 자식 요소 컴포넌트도 리렌더링 된다.

profile
아자자자

0개의 댓글