엘리스 AI 트랙 06주차 - React 기초 II (1/29) 🔥
✔ 06주차. 웹 프론트엔드 I
<학습 목표>
-
React(리액트)에 대한 가장 기본적인 개념을 학습합니다.
-
React를 사용해 다양한 컴포넌트를 만들고 이를 조합해 하나의 App을 구현합니다.
-
Bootstrap(부트스트랩)의 기본 개념과 여러가지 요소를 활용하여 React 웹 사이트에 적용합니다.
[01 Props]
1. 컴포넌트의 재사용
- 코드의 재사용이 중요한 이유 : 코드 유지보수성 향상, 코드 재사용이 용이, 가독성 향상
- 컴포넌트 합성 : 컴포넌트 안에서 다른 컴포넌트 참조가능.
function Hello(props) {
return <h1>Hello, {props.name}</h1>;
}
function Greeting() {
return (
<div>
<Hello name="Sara" />
<Hello name="Cahal" />
<Hello name="Edite" />
</div>
);
}
ReactDOM.render(<Greeting />, document.getElementById('root'));
- 컴포넌트 추출 : 한 컴포넌트가 복잡하다면 일부를 추출해서 분리하는 것이 가독성이 좋고 코드 재사용이 용이
// 추출 전 컴포넌트
function Comment(props){
return(
<div>
<div className="UserInfo"> {props.name}님의 할일 </div>
<div className="Todo">
<div>{props.todo.task1}</div>
<div>{props.todo.task2}</div>
</div>
</div>
);
}
// Todo 반환하는 컴포넌트
function Todo(props) {
return (
<div className="Todo">
<div>{props.todo.task1}</div>
<div>{props.todo.task2}</div>
</div>
);
}
// 유저 정보 반환하는 컴포넌트
function UserInfo(props) {
return (
<div>{props.name}님의 할일 </div>
);
}
// 출력 컴포넌트
function Comment(props){
return(
<div>
<UserInfo name={props.name}/>
<Todo todo={props.todo}/>
</div>
);
}
2. Props
- Props : 컴포넌트로 전달되는 매개변수 (=함수의 매개변수)
[02 State&생명주기]
1. State
- State : 컴포넌트 안에서 관리되는 렌더링 결과물에 영향을 주는 데이터를 갖고 있는 객체 (Props : 함수 매개변수처럼 사용 / State : 함수 내에 선언된 변수처럼 사용)
- Props와 State 차이 : Props는 부모 컴포넌트에서 자식 컴포넌트로 전달하는 값으로 자식 컴포넌트에서는 Props를 직접 수정할 수 없지만 State는 컴포넌트 내부에서 선언하며 내부에서 관리되는 값으로 값을 변경할 수 있음
→ Props는 읽기 전용으로 수정이 불가능하고, State는 원하는 경우 수정이 가능
2. setState()
- setState() : State를 변경하기 위해서 사용
3. 생명주기
- 생명주기 : Life cycle. 앱이 실행되고 종료되는 과정을 특정 시점 별로 나눠둔 것.
- React의 생명주기 : 컴포넌트가 이벤트를 다룰 수 있는 특정 시점을 말하며 마운트, 업데이트, 언마운트 상태로 구성
① 마운트 : 컴포넌트가 실제 DOM에 삽입되는 것
② 업데이트 : 컴포넌트가 변하는 것
④ 언마운트 : 컴포넌트가 DOM 상에서 제거되는 것
- 생명주기 메소드
① constructor(): State 데이터를 초기화 하는 메소드
② render(): 클래스 컴포넌트에서 반드시 구현되어야 하는 메소드
③ componentDidMount(): 컴포넌트가 마운트 된 직후 호출되는 메소드
④ componentDidUpdate(): 업데이트가 진행된 직후에 호출되는 메소드
⑤ componentWillUnmount(): 컴포넌트가 마운트 해제되어 제거되기 직전에 호출되는 메소드
[03 이벤트처리와 조건부 렌더링 및 Key 설정]
1. 이벤트 처리하기
- 이벤트 : 유저 행동의 결과 혹은 시스템에 의해 발생되는 일. onClick, OnChange, mouseover 등 React는 HTML과 동일한 이벤트 사용가능
- React 이벤트 특징
① 이벤트의 이름은 카멜(Camel) 표기법으로 기재
② 이벤트에 실행할 코드 전달 (X) 함수 형태의 객체를 전달 (O)
③ DOM요소에만 이벤트 설정 가능
- 이벤트 작성하기
① function 키워드를 사용해 이벤트 함수를 작성
② onClick={함수명} 으로 등록한 이벤트를 호출
function ActionLink() {
// function 키워드를 사용해 이벤트 함수를 작성
function handleClick(e) {
console.log('The link was clicked.');
}
return (
// onClick={함수명} 으로 등록한 이벤트를 호출
<a href="#" onClick={handleClick}>
Click me
</a>
);
}
- 이벤트 핸들링 하기
① 함수로 작성하여 핸들링 하기
② 함수 미리 작성 후, 핸들링
2. 조건부 렌더링(Conditional rendering) 알아보기
- 조건문 사용하기 : 조건문 if를 사용해 렌더링
// 로그인 한 사용자에게 보여주는 컴포넌트
function UserGreeting(props) {
return <h1>Welcome back!</h1>;
}
// 로그인하지 않은 사용자에게 보여주는 컴포넌드
function GuestGreeting(props) {
return <h1>Please sign up.</h1>;
}
function Greeting(props) {
// 2. render 에서 받은 props 를 isLoggedIn 변수로 저장
const isLoggedIn = props.isLoggedIn;
// 3. isLoggedIn 변수값에 따라 보여주는 것이 다름
if (isLoggedIn) {
return <UserGreeting />;
}
return <GuestGreeting />;
}
ReactDOM.render(
// 1. Greeting 함수를 불러올때 props 로 isLoggedIn 을 함께 넘김
<Greeting isLoggedIn={false} />,
document.getElementById('root')
);
- element variables : react element를 변수에 저장
// 로그인 버튼 컴포넌트
function LoginButton(props) {
return (
<button onClick={props.onClick}>
Login
</button>
);
}
// 로그아웃 버튼 컴포넌트
function LogoutButton(props) {
return (
<button onClick={props.onClick}>
Logout
</button>
);
}
// LoginControl 이라는 state를 가진 컴포넌트
class LoginControl extends React.Component {
constructor(props) {
super(props);
this.handleLoginClick = this.handleLoginClick.bind(this);
this.handleLogoutClick = this.handleLogoutClick.bind(this);
this.state = {isLoggedIn: false};
}
handleLoginClick() {
this.setState({isLoggedIn: true});
}
handleLogoutClick() {
this.setState({isLoggedIn: false});
}
render() {
const isLoggedIn = this.state.isLoggedIn;
let button = null;
if (isLoggedIn) {
button = <LogoutButton onClick={this.handleLogoutClick} />;
} else {
button = <LoginButton onClick={this.handleLoginClick} />;
}
return (
<div>
<!-- Greeting 불러오면서 props 로 isLoggedIn 넘김 -> 상태 확인후 사용자/게스트 맞춰서 보여줌 -->
<Greeting isLoggedIn={isLoggedIn} />
{button}
</div>
);
}
}
ReactDOM.render(
<LoginControl />,
document.getElementById('root')
);
- JSX로 구현하기
① && 연산자 사용
// && 연산자 사용
function Mailbox(props) {
const unreadMessages = props.unreadMessages;
return (
<div>
<h1>Hello!</h1>
<!-- props 로 받은 읽지않은 메세지가 0개 이상일때 -->
{unreadMessages.length > 0 &&
<!-- 이 아래 문장이 출력됨, 0일때는 출력되지 않음 -->
<h2>
You have {unreadMessages.length} unread messages.
</h2>
}
</div>
);
}
const messages = ['React', 'Re: React', 'Re:Re: React'];
ReactDOM.render(
<Mailbox unreadMessages={messages} />,
document.getElementById('root')
);
② 3항 연산자로 조건부 렌더링 구현하기
// 3항 연산자 사용
function Check(props){
const data = parseInt(props.num);
return(
<div>
{ data <= 0 ? <h2>양수가 아닙니다.</h2> : <h2>양수입니다.</h2> }
</div>
)
}
class InputData extends React.Component {
state = {
num: ''
}
handleChange = (e) => {
this.setState({
num: e.target.value
})
}
render() {
return (
<form>
숫자를 입력하세요: <input
value={this.state.num}
onChange={this.handleChange}
/>
{<Check num={this.state.num}/>}
</form>
);
}
}
ReactDOM.render(<InputData />,document.getElementById('root'));
3. Lists and Keys
- List
- 리스트 만들기
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((numbers) =>
<li>{numbers}</li>
);
ReactDOM.render(
<ul>{listItems}</ul>,
document.getElementById('root')
);
- 컴포넌트들로 구성된 리스트를 반환하는 컴포넌트 : 태그마다 유니크한 key값을 주어야 함
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li>{number}</li>
);
return (
<ul>{listItems}</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
<!-- 이 코드를 실행하면, 리스트 아이템에 키를 넣어야한다는 경고가 표시됩니다. -->
<!-- “키(key)“는 요소 리스트를 만들 때 포함해야하는 특수한 문자열 속성입니다. -->
- Key : 어떤 아이템이 바뀌었는지, 혹은 추가되었는지, 혹은 삭제되었는지를 인식할 수 있게 함. 요소에 안정적인 ID를 제공하려면 배열 내부 요소에 키를 주어야 함
- Key를 추가하기
// 키를 선택하는 가장 좋은 방법은 리스트 아이템의 형제 중
// 리스트 아이템을 고유하게 식별할 수 있는 문자열을 사용하는 것입니다.
// 대부분의 경우 데이터의 ID를 키로 사용합니다.
const todoItems = todos.map((todo) =>
<li key={todo.id}>
{todo.text}
</li>
);
// 만약 렌더링된 아이템에서 사용할 안정적인 ID가 없다면,
// 아이템 인덱스를 키로 넣어 추후에 다시 정렬할 수도 있습니다.
const todoItems = todos.map((todo, index) =>
// Only do this if items have no stable IDs
<li key={index}>
{todo.text}
</li>
);
- key로 컴포넌트 추출하기
// 키는 주변 배열의 컨텍스트에서만 의미가 있습니다.
// 예를 들어, ListItem 컴포넌트를 추출 한 경우, ListItem 자체의 루트 <li> 요소가 아닌
// 배열의 <ListItem /> 요소가 키를 가지고 있어야합니다.
function ListItem(props) {
const value = props.value;
return (
// Wrong! There is no need to specify the key here:
<li key={value.toString()}>
{value}
</li>
);
}
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
// Wrong! The key should have been specified here:
<ListItem value={number} />
);
return (
<ul>
{listItems}
</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
- 키는 형제 중에서 고유한 값이어야 함 : 글로벌로 유니크할 필요는 없음. 두 다른 배열을 생성할 때 동일한 키를 사용할 수 있다.
function Blog(props) {
const sidebar = (
<ul>
{props.posts.map((post) =>
<li key={post.id}>
{post.title}
</li>
)}
</ul>
);
const content = props.posts.map((post) =>
<div key={post.id}>
<h3>{post.title}</h3>
<p>{post.content}</p>
</div>
);
return (
<div>
{sidebar}
<hr />
{content}
</div>
);
}
const posts = [
{id: 1, title: 'Hello World', content: 'Welcome to learning React!'},
{id: 2, title: 'Installation', content: 'You can install React from npm.'}
];
ReactDOM.render(
<Blog posts={posts} />,
document.getElementById('root')
);
- JSX에서 map() 포함하기 : JSX는 중괄호를 이용하면 모든 표현식을 포함 할 수 있기 때문에 map() 도 인라인으로 포함시킬 수 있음
function NumberList(props) {
const numbers = props.numbers;
return (
<ul>
{numbers.map((number) =>
<ListItem key={number.toString()}
value={number} />
)}
</ul>
);
}
프론트랑 진짜 안맞는다...ㅎ 때려치고 싶음
※ 수업 자료의 출처는 K-Digital Training x 엘리스 인공지능 서비스 개발 기획 1기 (elice.io/) 및 리액트 공식문서 (ko.reactjs.org/) 입니다.