[코딩온] 프론트엔드 입문 Day 40 (React JSX, props)
오늘은 React의 JSX, props에 대해서 배웠다. 리더님의 설명을 듣고 직접 코드를 작성해보면서 분명히 알 것 같은데 약간 헤맸어서, 블로그에 학습내용을 정리하면서 개념을 확실히 기억하려고 한다.

JSX (JavaScript + XML)
자바스크립트 확장 문법. Babel을 이용해 일반 JS 코드로 변환해준다.
JSX의 기본적인 사용법이자 특징 5가지가 있는데,
export default function FunctionComponent() {
return(
<>
<div>함수형 컴포넌트 사용하기</div>
</>
);
};
1. HTML 태그는 반드시 단 하나의 부모 요소가 전체를 감싸는 형태로, return 키워드 소괄호 내부에 작성한다.
만약 반환할 태그가 하나인 경우에는 소괄호 필요없음.
→ virtual DOM에서 컴포넌트의 변화를 감지할 때, 효율적으로 비교할 수 있도록 컴포넌트 내부가 하나의 DOM tree 구조여야 한다고 React가 정한 규칙이다. 불필요한 태그를 만들지 않기 위해 (아무 텍스트로 입력하지 않은) fragment 태그를 사용하기도 한다. fragment 태그는 오직 묶어주는 용도로만 사용되고, 브라우저의 개발자도구에서 보이지 않는다.
※ React 공식문서 https://react.dev/reference/react/Fragment
export default function FunctionComponent() {
const text = '안녕하세요!';
const name = 'Mommy';
const show = true;
const checkUser = () => {
if (name === 'Mommy') {
return '안녕하세요!';
} else if (name === 'uncle') {
return '오랜만입니다!';
} else {
return '저리가!';
}
};
return(
<>
{/* 변수 사용하기 */}
<div>인사는 {text}</div>
{/* 삼항연산자 사용한 조건부 렌더링, 만든 함수 불러오기 */}
<h3>{name == 'Mommy' ? `어서오세요, ${name}님!` : '누구세요?'}</h3>
<h3>{checkUser()}</h3>
{/* && 연산자 사용한 조건부 렌더링 */}
<h3>{show && '모달창 넣어주기!'}</h3>
</>
);
};
2. HTML을 작성하다가 JS를 작성하고 싶다면 중괄호로 감싸면 된다.
중괄호 안에 소괄호로 묶으면 HTML도 넣을 수 있다.
삼항연산자 사용은 가능하지만 if문이나 for문은 사용할 수 없다.
→ 만약 사용해야 한다면 return 위에서 결과값을 저장하여 사용해야 한다.
export default function FunctionComponent() {
const textStyle = { backgroundColor: 'navy', color: 'pink', fontWeight: 900 };
return(
<>
<div style={{ backgroundColor: 'pink', color: 'navy', fontWeight: 900 }}>
Hello!
</div>
<div style={textStyle}>안녕?</div>
</>
);
};
3. CSS를 inline style로 적용할 때는 객체 형태로, 속성명은 camelCase로 작성한다.
객체를 return 위에서 변수에 담아서 중괄호 안에 입력하는 방식으로 사용할 수도 있다.
CSS를 작성할때 중괄호가 2개 들어가는데, 외부는 style을 묶은 것이고 내부는 객체를 의미한다.
export default function FunctionComponent() {
const handleClick = () => {
alert('클릭했다!!');
};
return(
<>
<div className="text-css">JSX에서 CSS 사용하기 (className)</div>
<button onClick={() => {alert('클릭');}}>버튼1</button>
<button onClick={handleClick}>버튼2</button>
</>
);
};
4. class, onclick의 사용법이 달라진다.
'클래스'라는 문법이 이미 존재하기 때문에 속성명을 className이라고 해야 하고, onClick이라고 해야한다.
위 코드의 경우, '버튼1'은 바로 함수를 선언하는 방식인데, JSX에서의 기본적인 onClick 사용방법이다.
'버튼2'는 return 이전에 선언한 함수를 불러와서 사용하는 방법이고, 클릭하기 전에 실행되면 안되니까 소괄호 입력 금지.
import cat from '../assets/cat.jpeg';
export default function FunctionComponent() {
return(
<>
<img src="/logo192.png" alt="react" />
<img src={cat} alt="cat" style={{ width: 200 }} />
</>
);
};
5. 빈 태그도 반드시 self closing이나 닫는 태그로 닫아줘야 한다. 태그와 컴포넌트 모두 동일하다.
참고로 img 태그의 경우, 절대경로는 public 폴더부터 잡히게 된다.
src 폴더에 있는 파일에서 이미지를 넣으려면 해당 이미지를 import 해야한다.
※ 프로젝트를 진행할 때, favicon이나 중요한 파일들은 전부 public 폴더에, 나머지 img나 icon 등은 전부 src 폴더에 assets라는 폴더를 만들어서 보관해야 한다.
React - Props
props는 properties의 줄임말로, 컴포넌트 속성을 설정할 때 사용하는 요소이다.
상위에서 하위로 흘러가는, 단방향 데이터 흐름을 갖고 있다. 여기서부터는 확장자로 jsx를 사용한다.
함수형 컴포넌트의 props
부모 컴포넌트에서 전달한 props는 함수의 파라미터로 전달받고, JSX 내부에서 중괄호로 감싸서 사용한다.
함수형 컴포넌트에서 props를 사용하는 방법은 5가지 정도가 있다.
// app.js
import FuncProps from './components/FuncProps';
function App() {
return (
<div className="App">
<FuncProps weather='sunny' feeling='happy' />
</div>
);
}
export default App;
// FuncProps.jsx
export default function FuncProps(props) {
return (
<>
<h1>함수형 컴포넌트에서 props 사용</h1>
<div><b>전달받은 props 객체를 점 접근법으로 바로 접근해 사용</b></div>
<div>weather props로 전달받은 데이터 : {props.weather}</div>
<div>feeling props로 전달받은 데이터 : {props.feeling}</div>
</>
);
}
1. props라는 매개변수를 받는 방식
부모 요소에서 props로 전달한 데이터가 props 내부에 객체 형태로 저장된다.
자식 요소에서 점 접근법을 이용해 바로 가져와서 사용할 수 있다.
// FuncProps.jsx
export default function FuncProps(props) {
const { weather, feeling } = props;
return (
<>
<h1>함수형 컴포넌트에서 props 사용하기</h1>
<div>
<b>전달받은 props 객체를 구조분해하여 사용</b>
</div>
<div>weather props로 전달받은 데이터 : {weather}</div>
<div>feeling props로 전달받은 데이터 : {feeling}</div>
</>
);
}
2. 컴포넌트 내에서 props 매개변수를 구조분해하여 사용하기
return 이전에 props를 구조분해하여 정의를 내려놓고, return 안에서 데이터(속성)만 불러와서 사용한다.
// FuncProps.jsx
export default function FuncProps({ weather, feeling }) {
return (
<>
<h1>함수형 컴포넌트에서 props 사용하기</h1>
<div>
<b>매개변수로 props를 받아올 때부터 구조분해하여 사용</b>
</div>
<div>weather props로 전달받은 데이터 : {weather}</div>
<div>feeling props로 전달받은 데이터 : {feeling}</div>
</>
);
}
3. 매개변수로 props를 받아올 때부터 구조분해 시키기
앞선 방법에서는 "props를 이렇게 구조분해 시켰다" 라고 정의를 내려놓고 매개변수로 props를 넣었지만, 여기서는 그런 과정을 생략하고 바로 구조분해한 형태를 매개변수로 넣는다.
// app.js
import FuncProps from './components/FuncProps';
function App() {
return (
<div className="App">
<FuncProps feeling='exciting' date='20240405'/>
</div>
);
}
export default App;
// FuncProps.jsx
import PropTypes from 'prop-types';
export default function FuncProps({ weather, feeling, date }) {
return (
<>
<h1>함수형 컴포넌트에서 props 사용하기</h1>
<div>
<b>default props로 weather props만 보여주기</b>
</div>
<div>오늘의 날짜는 {date}</div>
<div>weather props로 전달받은 데이터 : {weather}</div>
<div>feeling props로 전달받은 데이터 : {feeling}</div>
</>
);
}
FuncProps.defaultProps = {
weather: 'cloudy',
};
FuncProps.propTypes = {
weather: PropTypes.string,
feeling: PropTypes.string,
date: PropTypes.number.isRequired,
};
4. defaultProps와 propTypes 사용하기
defaultProps는 부모 요소에서 props가 전달되지 않았을 때 기본적으로 들어갈 props를 설정하는 기능이다.
propTypes는 props의 타입을 지정할 때 사용하는데, JS의 유연성을 해결하기 위해 권장되는 기능이다.
다른 타입으로 정보가 전달되어도 동작하지만, 콘솔에서 error를 확인할 수 있다.
※ isRequired는 필수적으로 해당 props를 전달하라고 제한하는 키워드, 전달 안하면 콘솔에 error가 뜬다.
/* app.js */
import FuncProps from './components/FuncProps';
function App() {
const sayHi = () => {
alert('안녕?');
};
return (
<div className="App">
// 문자열 보내기
<FuncProps>안녕?</FuncProps>
// 함수 보내기
<FuncProps>{sayHi}</FuncProps>
// 요소 보내기
<FuncProps>
<div>안녕하세요</div>
<div>hello~</div>
</FuncProps>
</div>
);
}
export default App;
/* FuncProps.jsx */
import PropTypes from 'prop-types';
export default function FuncProps(props) {
return <div>{props.children}</div>;
}
// 함수 전달
export default function FuncProps(props) {
return <div onClick={props.children}>클릭!</div>;
}
// 요소 전달
export default function FuncProps(props) {
return <>{props.children}</>;
}
5. props.children 사용하기
부모 요소에서 해당 컴포넌트가 import되어 컴포넌트의 컨텐츠를 가지고 와야하는 경우에 사용한다.
클래스형 컴포넌트의 props
기본적인 형식은 아래와 같다.
render()는 화면에 컴포넌트를 표시하기 위해 작성하는 함수이다.
/* app.js */
import ClassProps from './components/ClassProps';
function App() {
return (
<div className="App">
<ClassProps drink="americano" payment="card" price={4000} />
</div>
);
}
export default App;
/* ClassProps.jsx */
export default class ClassProps extends Component {
render() {
console.log(this.props);
// 객체 {drink: 'americano', payment: 'card'} 출력
return (
<>
<h1 className="title">클래스형 컴포넌트의 props 사용</h1>
<div>
주문하신 음료는 {this.props.drink}이고, 결제는 {this.props.payment}
입니다.
</div>
<div>가격은 {this.props.price}입니다.</div>
</>
);
}
클래스 컴포넌트 props 속성 추가 방법 1.
defaultProps는 static 키워드 사용하여 컴포넌트 선언 내부(render 함수 바깥)에 입력한다.
/* app.js */
import ClassProps from './components/ClassProps';
function App() {
return (
<div className="App">
<ClassProps drink="아인슈페너" payment="현금" />
</div>
);
}
export default App;
/* ClassProps.jsx */
export default class ClassProps extends Component {
render() {
return (
<>
<h1 className="title">클래스형 컴포넌트의 props 사용</h1>
<div>
주문하신 음료는 {this.props.drink}이고,
결제는 {this.props.payment}입니다.
</div>
<div>가격은 {this.props.price}입니다.</div>
</>
);
}
static defaultProps = {
price: 8500,
// price가 undefined일때 출력됨
};
}
클래스 컴포넌트 props 속성 추가 방법 2.
컴포넌트 선언문 밖에서 점 접근법으로 속성을 지정한다.
아래 코드에서는 drink가 string으로 지정되어 있는데 숫자 {15900}이 들어와서 error가 발생하게 된다.
'레몬에이드'는 payment가 isRequired로 필수 사용하도록 지정되어 있는데 해당 속성이 없어서 error가 발생한다.
/* app.js */
import ClassProps from './components/ClassProps';
function App() {
return (
<div className="App">
<ClassProps drink={15900} payment="현금" />
<ClassProps drink="레몬에이드" />
</div>
);
}
export default App;
/* ClassProps.jsx */
export default class ClassProps extends Component {
render() {
return (
<>
<h1 className="title">클래스형 컴포넌트의 props 사용</h1>
<div>
주문하신 음료는 {this.props.drink}이고,
결제는 {this.props.payment}입니다.
</div>
<div>가격은 {this.props.price}입니다.</div>
</>
);
}
}
ClassProps.propTypes = {
drink: PropTypes.string,
payment: PropTypes.string.isRequired, // payment는 필수 값으로 지정
price: PropTypes.number,
};
여기까지가 오늘 배운 내용이었다. 지난 포스팅에서도 얘기했지만, 쉬운듯 하면서도 만만하지 않아서 연구와 실험을 조금 더 부지런히 해야할 것 같다.😂
얼른 오늘자 과제를 하며 React와 친해져봐야지..
