1. 컴포넌트 기반 구조
- 리액트를 컴포넌트 기반이라고 부르는 것은 작은 컴포넌트들이 모여서 하나의 컴포넌트를 구성하고, 또 이러한 컴포넌트들이 모여 전체 페이지를 구성하기 때문
- 하나의 컴포넌트를 반복적으로 사용함으로써 전체 코드의 양이 줄어 개발 시간과 유지 보수 비용을 줄일 수 있음
- 리액트 컴포넌트는 어떠한 속성들을 입력받아서 그에 맞는 리액트 엘리먼트를 생성하여 리턴해줌
- 리액트 컴포넌트는 만들고자 하는대로 props(속성)을 넣으면 해당 속성에 맞춰 화면에 나타날 엘리먼트를 만들어 주는 것
2. Props
- 리액트 컴포넌트의 속성
- 리액트 컴포넌트는 붕어빵 틀, Element는 붕어빵 틀에서 만들어진 붕어빵, props는 붕어빵에 들어가는 재료
- props는 같은 리액트 컴포넌트에서 눈에 보이는 글자나 색깔 등의 속성을 바꾸고 싶을 때 사용하는 컴포넌트의 속 재료
- props는 컴포넌트에 전달할 다양한 정보를 담고 있는 자바스크립트 객체
3. Props의 특징
- Props의 중요한 특징은 읽기 전용(Read-only)라는 것
- All React componenets must act like pure functions with respect to their props
- 모든 리액트 컴포넌트는 props를 직접 바꿀 수 없고, 같은 props에 대해서는 항상 같은 값을 보여줘야 함
pure 함수
- input을 변경하지 않으며 같은 input에 대해서 항상 같은 output을 리턴
function sum(a,b) {
return a+b;
}
impure 함수
- input을 변경
function withdraw(accout, amount) {
account.total -= amount;
}
- 리액트 컴포넌트에 입력으로 들어오는 props는 자바스크립트 함수의 파라미터와 같음
- 함수가 Pure하다는 것은 함수의 입력값인 파라미터를 바꿀 수 없다는 의미를 포함
4. props의 사용법
- 컴포넌트에 props라는 객체를 전달하는 방법
1) JSX를 사용하는 경우
- 키-값 쌍의 형태로 컴포넌트에 props를 넣을 수 있음
ex) App 컴포넌트
function App(props) {
return (
<profile
name="소플"
introduction="안녕하세요, 소플입니다."
viewCount={1500}
/>
);
}
- name, introduction, viewCount 속성의 값이 모두 Profile 컴포넌트에 props로 전달되며 props는 자바스크립트 객체가 됨
{
name="소플",
introduction="안녕하세요, 소플입니다.",
viewCount=1500
}
ex)
App 컴포넌트
function App(props) {
return (
<Layout
witdh={2560}
height={1440}
header={
<header title="소플의 블로그입니다."/>
}
footer={
<Footer/>
}
/>
);
}
- Layout 컴포넌트의 props로는 정숫값을 가진 witdh, height와 리액트 엘리먼트인 header, footer가 들어오게 됨
2) JSX를 사용하지 않는 경우
리액트의 createElement() 함수
React.createElement (
type
[props],
[...children]
)
- 두 번째 파라미터인 props에 자바스크립트 객체를 넣으면 그게 곧 해당 컴포넌트의 props가 됨
React.creaetElement (
Profile,
{
name : "소플",
introduction : "안녕하세요, 소플입니다.",
viewCount: 1500
},
null
);
- 타입은 컴포넌트의 이름인 Profile이 들어가고 props로 자바스크립트 객체라 들어감
- children에는 하위 컴포넌트가 없기 때문에 null이 들어감
5. 컴포넌트 만들기
1) 함수 컴포넌트
- 리액트의 컴포넌트는 일종의 함수
ex)
- 하나의 props 객체를 받아서 인사말이 담긴 리액트 엘리먼트를 리턴
function Welcome(props) {
return <h1>안녕, {props.name}</h1>;
}
2) 클래스 컴포넌트
- 자바스크립트의 ES6의 클래스(class)라는 것을 사용해서 만들어진 형태의 컴포넌트
- React.Component를 상속 받아서 만듬
ex)
- React.Component 클래스를 상속받아서 Welcome 이라는 클래스를 만듬
class Welcome extends React.Component {
render() {
return <h1>안녕, {this.props.name}</h1>;
}
}
6. 컴포넌트 렌더링
- 렌더링을 위해서는 먼저 컴포넌트로부터 엘리먼트를 만들어야 함
- Welcom 함수 컴포넌트 선언
- <Welcome name="인제"/>라는 값을 가진 엘리먼트를 파라미터로 해서 ReactDOM.render()를 호출
- 리액트는 Welcome 컴포넌트에 { name:"인제"}라는 props를 넣어서 호출하고 그 결과로 리액트 엘리먼트가 생성
- 생성된 엘리먼트는 최종적으로 React DOM을 통해 실제 DOM에 효과적으로 업데이트되고 사용자가 브라우저를 통해서 볼 수 있게 됨
function Welcome(props) {
return <h1>안녕, {props.name} </h1>;
}
const element = <Welcome name="인제" />;
ReactDOM.render (
element,
document.getElementById('root')
);
6. 컴포넌트 합성
컴포넌트 합성 (Composing Components)
- 여러 개의 컴포넌트를 합쳐서 하나의 컴포넌트를 만드는 것
- 리액트에서는 컴포넌트 안에 또 다른 컴포넌트를 사용할 수 있기 때문에, 복잡한 화면을 여러 개의 컴포넌트로 나눠서 구현할 수 있음
ex)
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 컴포넌트를 3개를 포함한 컴포넌트
- App 컴포넌트 안에 3개의 Welcome 컴포넌트가 있고, 각각의 Welcome 컴포넌트는 각기 다른 Props를 가지고 있음
7. 컴포넌트 추출
컴포넌트 추출(Extracting component)
- 큰 컴포넌트에서 일부를 추출해서 새로운 컴포넌트를 만듬
- 컴포넌트의 재사용성이 향상됨
-> 컴포넌트가 작아질수록 해당 컴포넌트의 기능과 목적이 명확해지고, props도 단순해짐
- 기능단위로 구분하는 것이 좋고, 나중에 곧바로 재사용이 가능한 형태로 추출하는 것이 좋음
Comment 컴포넌트
- 댓글을 표시하기 위한 컴포넌트로 내부에 작성자의 프로필 이미지와 이름 그리고 댓글 내용과 작성일 포함
function Comment(props) {
return (
<div className="comment">
<div className="user-info">
<img className="avatar"
src={props.author.avartaUrl}
alt={props.author.name}
/>
<div className="user-info-name">
{props.author.name}
</div>
</div>
<div className="comment-text">
{props.text}
</div>
<div className="comment-date">
{formatDate(props.data)};
</div>
</div>
);
}
1) Avarter 컴포넌트 추출
Avarter 컴포넌트
- 사용자의 프로필 이미지 표시
function Avatar(props) {
return (
<img className="avatar"
src={props.user.avatarUrl}
alt={props.user.name}
/>
);
}
- Avarter 컴포넌트를 Comment 컴포넌트에 반영
function Comment(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-date">
{formatDate(props.data)};
</div>
</div>
);
}
2) User-Info 컴포넌트 추출
User-Info 컴포넌트
- 사용자의 정보를 담고 있음
- Avatar 컴포넌트도 함께 추출
function UserInfo(props) {
return (
<div className = "user-info">
<Avatar user={props.user} />
<div className="user-info-name">
{props.user.name}
</div>
</div>
);
}
- UserInfo 컴포넌트를 Comment 컴포넌트에 반영
function Comment(props) {
return (
<div className = "comemnt">
<UserInfo user={props.author} />
<div className="comment-text">
{props.text}
</div>
<div className="comment-data">
{formatDate(props.date)}
</div>
</div>
);
}
- 추출된 컴포넌트 구조
- Comment 컴포넌트가 UserInfo 컴포넌트를 포함하고 있고, UserInfo 컴포넌트가 Avatar 컴포넌트를 포함하고 있는 구조
8. 실습 - 댓글 컴포넌트 만들기
Comment.jsx | 댓글 컴포넌트 |
CommentList.jsx | 댓글 목록 컴포넌트 |
Comments | 댓글 데이터를 담고 있는 객체 |
Comment.jsx
import React from "react";
const styles = {
wrapper: {
margin: 8,
padding: 8,
display: "flex",
flexDirection: "row",
border: "1px solid grey",
borderRadius: 16,
},
imageContainer: {},
image: {
width: 50,
height: 50,
borderRadius: 25,
},
contentContainer: {
marginLeft: 8,
display: "flex",
flexDirection: "column",
justifyContent: "center",
},
nameText: {
color: "black",
fontSize: 100,
fontWeight: "bold",
},
commentText: {
color: "black",
fontSize: 100,
},
};
function Comment(props) {
return (
<div style = {styles.wrapper}>
<div style={styles.imageContainer}>
<img
src="https://upload.wikimedia.org/wikipedia/commons/8/89/Portrait_Placeholder.png"
alt={styles.image}
/>
</div>
<div style={styles.contentContainer}>
<span style={styles.nameText}>{props.name}</span>
<span style={styles.commentText}>{props.comment}</span>
</div>
</div>
);
}
export default Comment;
CommentList.jsx
- 댓글 데이터를 별도의 객체로 분리해서 동적으로 받아온 데이터를 표시할 수 있는 구조
- comments라는 배열을 만들어서 댓글 데이터를 담고 있는 객체들을 넣어줌
- map() 함수를 써서 각 댓글 객체에 대해서 Comment 컴포넌트를 리턴하도록 작성
import React from "react";
import Comment from "./Comment";
const comments = [
{
name:"이인제",
comment:"안녕하세요, 소플입니다.",
},
{
name:"유재석",
comment:"리액트, 재미있어요",
},
{
name:"아이유",
comment:"저도 리액트 배워보고 싶어요!!",
},
];
function CommentList(props) {
return (
<div>
{comments.map((comment) => {
return (
<Comment name={comment.name} comment={comment.comment} />
);
})}
</div>
);
}
export default CommentList;
'react' 카테고리의 다른 글
[소플] ch 7. 훅 (0) | 2023.10.27 |
---|---|
[소플] ch 6. state와 생명 주기 (0) | 2023.10.27 |
[소플] ch4. 엘리먼트 렌더링 (1) | 2023.10.27 |
[코드잇] 리액트로 웹 사이트 만들기 (0) | 2023.09.28 |
[코드잇] 리액트로 데이터 다루기(5) (0) | 2023.09.25 |