심심할 때쯤 복습해보는 리액트 공식문서
리액트에 대해 공부하다보면 어느순간
내가 알고있는 개념들에 빈 구멍이 많다는 것을 인식하게 된다.
이러한 순간이 다가올 때 공식문서를 보면 그 빈 틈세를 효과적으로 메울 수 있다고 생각한다.
React는 별도의 파일에 마크업과 로직을 넣어 기술을 인위적으로 분리하는 대신, 둘 다 포함하는 “컴포넌트”라고 부르는 느슨하게 연결된 유닛으로 관심사를 분리합니다.
중괄호{ }
안에는 유효한 모든 js표현식(:값)
을 넣을 수 있다.const element = (
<div>
<h1>Hello!</h1>
<img src={user.avatarUrl} />;
</div>
);
자바스크립트 객체로 평가
됩니다.if문 for
문 안에서 사용하고,변수에 할당
하고,인자
로 받아들이고,함수 반환값
으로 사용할 수 있다.태그가 비어있다면 XML처럼 \/> 를 이용해 바로 닫아주어야 합니다.
const element = <img src={user.avatarUrl} />;
jsx 태그는 자식을 포함할 수 있습니다.
const element = (
<div>
<h1>Hello!</h1>
<h2>Good to see you here.</h2>
</div>
);
이스케이프
특정 문자를 원래의 기능에서 벗어나게 변환하는 행위를 이스케이프(Escape:\)라고 한다.
&은 &로
<은 <로
은 >로
"은 "로
'은 '로
띄어쓰기는 로
//이를통해 HTML본연의 태그나 스크립트 기능이 제거되어
XSS공격을 방지할 수 있다.
Babel은 jsx를 React.createElement() 호출로 컴파일합니다.
다음 두 예시는 동일합니다.
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
React.createElement()는 버그가 없는 코드를 작성하는 데 도움이 되도록 몇 가지 검사를 수행하며, 기본적으로 다음과 같은 단순화된 객체를 생성합니다.
// 주의: 다음 구조는 단순화되었습니다
const element = {
type: 'h1',
props: {
className: 'greeting',
children: 'Hello, world!'
}
};
위와 같은 객체를 React.Element
라고 하고
React는 이 객체를 읽어서, DOM을 구성하고 최신 상태로 유지하는 데 사용합니다.(virtual DOM & diffing argo)
Element
는 React 앱의 가장 작은 단위
입니다.
일반적으로 React 엘리먼트는 1.일반 엘리먼트 2.사용자 정의 컴포넌트 를 의미합니다.
DOM 엘리먼트: DOM객체 (일반 plain 객체보다 무겁다)
React 엘리먼트: 일반 객체(plain)
<div id='root'></div>
// 루트DOM 노드
리액트 앱은 일반적으로
하나의 루트DOM노드
가 있음
이 안에 들어가는 모든 엘리먼트를 React DOM에서 관리한다.
const root = ReactDOM.createRoot( // 2. 노드 취득 후 root변수에 할당
document.getElementById('root') // 1.루트DOM노드(div id='root')취득(모든 하위 React.Elem를포함한다)
);
const element = <h1>Hello, world</h1>;
root.render(element); //root노드의 render()메서드에 전달후 호출
따라서,UI를 업데이트하는 유일한 방법은 새로운 엘리먼트를 생성하고 이를 root.render()로 전달하는 것입니다.
즉, React 엘리먼트(virtual dom을 구성)를 새로이 생성하여 전후 상태를 비교하는 알고리즘으로 UI를 업데이트(리렌더)함을 의미.
function Welcome(props) { ///...컴포넌트명은 반드시 시작을 대문자로!
return <h1>Hello, {props.name}</h1>;
}
전까지는 DOM 태그만을 사용해 React 엘리먼트를 나타냈습니다.
const element = <div />; ///... 일반 엘리먼트도 React 엘리먼트입니다.
React 엘리먼트는 사용자 정의 컴포넌트로도 나타낼 수 있습니다.
const element = <Welcome name="Sara" />; ///...사용자 정의 컴포넌트
React가 사용자 정의 컴포넌트로 작성한 엘리먼트를 발견하면 jsx 어트리뷰트와 자식을 해당 컴포넌트에 단일 객체로 전달합니다. 이 객체를 “props”라고 합니다.
다음은 페이지에 “Hello, Sara”를 렌더링하는 예시입니다.
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
const root = ReactDOM.createRoot(document.getElementById('root')); //1.루트돔노드(모든React.Elem를 포함한 상위노드)
const element = <Welcome name="Sara" />;
root.render(element); //2. 루트돔 node의 render메서드에 react elem를 넣어 호출 =>UI렌더링 이뤄짐.
위 예시에서는 다음과 같은 일들이 일어납니다.
- <Welcome name="Sara" /> (jsx로 작성된 리액트엘리먼트)로
root.render()를 호출합니다.
- React는 {name: 'Sara'}를 props로 하여 Welcome 컴포넌트를 호출합니다.
- Welcome 컴포넌트는 결과적으로
<h1>Hello, Sara</h1>
엘리먼트를 반환합니다.- React DOM은
<h1>Hello, Sara</h1>
엘리먼트와 일치하도록 DOM을 효율적으로 업데이트합니다.
const { 변수명 } //변수패턴 = 분해할 객체
function sum(a, b) {
return a + b;
}
순수함수
라고 호칭하고,반면, 다음 함수는 자신의 입력값을 변경하기 때문에 순수 함수가 아닙니다.
function withdraw(account, amount) {
account.total -= amount;
}
모든 React 컴포넌트는 자신의 props를 다룰 때 반드시 순수 함수처럼 동작해야 합니다.
물론 애플리케이션 UI는 동적이며 시간에 따라 변합니다. 이러한 문제를 해결하기위해
State
가 존재합니다. React 컴포넌트는 state를 통해 위 규칙을 위반하지 않고 사용자 액션, 네트워크 응답 및 다른 요소에 대한 응답으로 시간에 따라 자신의 출력값을 변경할 수 있습니다.
컴포넌트는 자신의 출력에 다른 컴포넌트를 참조할 수 있습니다.
예를 들어 Welcome을 여러 번 렌더링하는 App 컴포넌트를 만들 수 있습니다.
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
function App() {
return (
<div>
<Welcome name="Sara" />
<Welcome name="Cahal" />
<Welcome name="Edite" />
</div>
);
}
너무 heavy한 컴포넌트는 여러 개의 작은 컴포넌트로 나누는 것이 가능합니다.
컴포넌트는 마운트,업데이트,언마운트의 생명주기를 가집니다.
e 합성이벤트 객체
가 인자로 전달됩니다.[HTML]
<button onclick="activateLasers()">
Activate Lasers
</button>
[jsx]
<button onClick={activateLasers}> //camelCase , {함수, not 문자열 }
Activate Lasers
</button>
e.preventDefault()
로 onSubmit
이벤트의 기본동작을 명시적으로 방지해줘야합니다.function Form() {
function handleSubmit(e) {
e.preventDefault();
console.log('You clicked submit.');
}
return (
<form onSubmit={handleSubmit}>
<button type="submit">Submit</button>
</form>
);
}
const 변수 = React엘리먼트
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;
if (isLoggedIn) {
button = <LogoutButton onClick={this.handleLogoutClick} />; //엘리먼트 변수
} else {
button = <LoginButton onClick={this.handleLoginClick} />;
}
return (
<div>
<Greeting isLoggedIn={isLoggedIn} />
{button}
</div>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<LoginControl />);
jsx 안에는 if문을 사용할 수 없지만 대신 중괄호에 js표현식을 포함 할 수 있습니다.
true && expression
은 항상 expression
으로 평가된다. (둘 다 참이여야 참)false && expression
은 항상 false
true &&
뒤에오는 표현식으로 평가되고, false는 falsefunction Mailbox(props) {
const unreadMessages = props.unreadMessages;
return (
<div>
<h1>Hello!</h1>
{unreadMessages.length > 0 && ///...앞에값이 true일 때, 뒤에 출력
<h2>
You have {unreadMessages.length} unread messages.
</h2>
}
</div>
);
}
const messages = ['React', 'Re: React', 'Re:Re: React'];
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Mailbox unreadMessages={messages} />);
render() {
const count = 0;
return (
<div>
{count && <h1>Messages: {count}</h1>}
</div>
);
}
삼항연산자 (조건식,값) ? A : B
로 If-Else 구문 인라인으로 표현하기표현식
이기 때문에 삼항연산자의 반환값
이 될 수 있음.render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
{isLoggedIn
? <LogoutButton onClick={this.handleLogoutClick} />
: <LoginButton onClick={this.handleLoginClick} />
}
</div>
);
}
null
) 렌더링 결과를 출력하는 대신 null을 반환
하면 해결할 수 있습니다.const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li>{number}</li>
);
표현식
이므로 자바스크립트 로직의 값으로 사용된다.고유하고(unique) & 안정적인(stable,변하지않는)
key속성값을 필요로한다.문자열
을 사용하는 것입니다.function ListItem(props) {
// 맞습니다! 여기에는 key를 지정할 필요가 없습니다.
return <li>{props.value}</li>;
}
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
// 맞습니다! 배열 안에 key를 지정해야 합니다.
<ListItem key={number.toString()} value={number} />
);
return (
<ul>
{listItems}
</ul>
);
}
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.'}
];
const content = posts.map((post) =>
<Post
key={post.id} //힌트로만 사용되는 값
id={post.id} //실제 명시적으로 전달되는 값
title={post.title} />
);
표현식(:값)
을 포함시킬 수 있다.function NumberList(props) {
const numbers = props.numbers;
return (
<ul>
{numbers.map((number) =>
<ListItem key={number.toString()}
value={number} /> //map()은 배열을 반환하므로 표현식이다.
)}
</ul>
);
}
HTML 폼 엘리먼트는 폼 엘리먼트 자체가 내부 상태
를 가지기 때문 React의 다른 DOM 엘리먼트와 다르게 동작합니다.
예를 들어, 순수한 HTML에서 아래의 폼은 name
을 입력받습니다.
<form>
<label>
Name:
<input type="text" name="name" />
</label>
<input type="submit" value="Submit" />
</form>
위 방식보다는 Javascript 함수로 폼의 제출을 처리하고, 사용자가 폼에 입력한 데이터에 접근하도록
하는 것이 편리합니다. => 이를 제어 컴포넌트
라고합니다.
HTML에서
<input>, <textarea>, <select>
와 같은 폼 엘리먼트는 일반적으로 사용자의 입력을 기반으로 자신의 state를 관리하고 업데이트합니다. React에서는 변경할 수 있는 state가 일반적으로 컴포넌트의 state 속성에 유지되며 setState()에 의해 업데이트됩니다.
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
HTML에서 <textarea>
엘리먼트는 텍스트를 자식으로 정의합니다.
<textarea>
Hello there, this is some text in a text area
</textarea>
React에서 <textarea>
는 value 어트리뷰트를 대신 사용합니다. 이렇게하면 <textarea>
를 사용하는 폼은 한 줄 입력을 사용하는 폼과 비슷하게 작성할 수 있습니다.
class EssayForm extends React.Component {
constructor(props) {
super(props);
this.state = {
value: 'Please write an essay about your favorite DOM element.'
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('An essay was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Essay:
<textarea value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
<textarea value={valueState}/>
형태로 value속성으로 관리한다.기존 HTML방식
<select>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option selected value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
React 제어컴포넌트 방식
<form onSubmit={this.handleSubmit}>
<label>
Pick your favorite flavor:
<select value={this.state.value} onChange={this.handleChange}>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
</label>
<input type="submit" value="Submit" />
</form>
제어 컴포넌트에
value prop을 지정하면 의도하지 않는 한 사용자가 변경할 수 없습니다.
value를 설정했는데 여전히 수정할 수 있다면? 실수로 undefined, null로 설정되었을 경우 뿐입니다.ReactDOM.createRoot(mountNode).render(<input value="hi" />); ///... input value prop이 'hi'로 고정되어 변경이 불가능합니다. setTimeout(function() { ReactDOM.createRoot(mountNode).render(<input value={null} />); }, 1000); ///... 1초 뒤 input 입력이 활성화됩니다.
출처:
[리액트공식문서]
3.엘리먼트렌더링
4.Component와Props
6.이벤트 처리하기
7. 조건부렌더링
8. 리스트와 Key
9. Form
+ 나의 작은 견해