React | 생활코딩
Virtual DOM | velopert
리액트 초심자를 위한 핵심 강좌 | velopert
Virtual DOM in simple English
Function component vs. Class component
Stateless component vs. Stateful component
Complete Intro React
React Basics: State, Props & Functional Components
⭐︎React 공식문서: React 12 main concepts
⭐︎React 공식문서: Practical Tutorial
React 공식문서(한국어)
React 공식문서 번역
※ JavaScript Tutorial
JavaScript
Modern.js
const element = <h1>Hello, world!</h1>;
: (HTML과 비슷해 보이지만) JavaScript의 확장 문법
1) 반드시 하나의 element로 감싸야 한다.
<div>
<div>
<h1>React</h1>
</div>
<div>
<h2>JSX</h2>
</div>
</div>
2) 자바스크립트 코드를 적용할 땐, {}(중괄호) 안에 작성
const name = 'Miranda Hart';
const element = <h1>Hello, {name}</h1>;
3) JSX 내부에선 if문 사용 불가 —> IIFE or 삼항 연산자 사용
<div>
{
(1 + 1 === 2) ? (<h1>정답</h1>) : (<h1>오답</h1>)
}
</div>
4) element의 클래스 이름 => className 사용
// ES6
<div class="app-container">App</div>
// JSX
<div className="app-container">App</div>
const name = 'Miranda Hart';
const element = <h1>Hello, {name}</h1>;
// name이라는 변수를 선언한 후 중괄호로 감싸 JSX 안에 사용
ReactDOM.render(
element,
document.getElementById('root')
);
function formatName(user) {
return user.firstName + ' ' + user.lastName;
}
const user = {
firstName: 'Miranda',
lastName: 'Hart'
};
// JS 함수 호출의 결과인 formatName(user)을 <h1> 엘리먼트에 포함
// * 2) 자바스크립트 코드를 적용할 땐, __{}(중괄호)__ 안에 작성
const element = (
<h1>
Hello, {formatName(user)}!
</h1>
);
// Split JSX over multiple lines for readability
// Recommend wrapping it in parentheses to avoid "automatic semicolon insertion".
// (ref: https://stackoverflow.com/questions/2846283/what-are-the-rules-for-javascripts-automatic-semicolon-insertion-asi)
ReactDOM.render(
element,
document.getElementById('root')
);
// Hello, Miranda Hart!
function getGreeting(user) {
if (user) {
return <h1>Hello, {formatName(user)}!</h1>;
}
return <h1>Hello, Stranger:)</h1>;
}
const element = <div tabIndex="0"></div>;
const element = <img src={user.avatarUrl}></img>;
// 다음 두 예시는 동일
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
// JSX는 Babel을 통해 React.createElement() 호출로 컴파일
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
// Note: 구조 단순화
const element = {
type: 'h1',
props: {
className: 'greeting',
children: 'Hello, world!'
}
};
※ ES6 및 JSX 코드가 올바르게 표시되도록 편집기에 Babel 언어 설정 사용하는 것을 권장
: React 앱의 가장 작은 단위; 화면에 표시할 내용을 기술
// root DOM Node
<div id="root"></div>
// To render a React element into a root DOM node, pass it to ReactDOM.render
const element = <h1>Hello, world</h1>;
ReactDOM.render(element, document.getElementById('root'));
function tick() {
const element = (
<div>
<h1>Hello, world!</h1>
<h2>It is {new Date().toLocaleTimeString()}.</h2>
</div>
);
ReactDOM.render(element, document.getElementById('root'));
}
setInterval(tick, 1000);
// 위 함수는 setInterval() 콜백을 이용해 1초마다 ReactDOM.render()를 호출
// Hello, world!
// It is 오후 8:13:22.(현재 시간)
// 내용이 변경된 텍스트 노드만 업데이트
Detailed component API
: 하나의 의미를 가진 독립적인 단위 모듈 (쉽게 말해 나만의 HTML 태그)
Components are the building blocks of a React application. They are reusable and independent blocks of code.
A Component is a function or a Class which optionally accepts input and returns a React element
Element & Component
// 데이터를 가진 하나의 “props” (props는 속성을 나타내는 데이터) 객체 인자를 받은 후 React 엘리먼트를 반환하는 유효한 React 컴포넌트
// * 함수 컴포넌트; JavaScript 함수
const myComponent => (props) {
return (
<elementOrComponent../>
);
}
// return JSX
// * 클래스 컴포넌트; ES6 Class
class myComponent extends React.Component {
render() {
return (
<elementOrComponent../>
);
}
}
// return JSX
This private internal state is what gives React its reactive nature. When the state of a class component changes, React will re-render that component in the browser.
(ref: https://medium.com/edge-coders/how-to-write-your-first-react-js-component-d728d759cabc)
Component | Fucntional | Class |
---|---|---|
장점 | (비교적)빠르다/재사용성/디버깅이 쉽다 | state, lifecycle API 사용 가능, (React.Component로부터 상속받음) |
단점 | state, lifecycle API 사용 불가 | 간결성 떨어진다 |
// * JSX
// Define a new function that returns an HTML button element
// button element in JSX will be compiled into JavaScript
function Button() {
return (
<button>Go</button>
);
}
// * actual javascript
// React.createElement function
function Button() {
return (
React.createElement("button", null, "Go")
);
}
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
// * 컴포넌트의 이름은 항상 대문자로 시작 (<Welcome />)
// 1. <Welcome name="Miranda" /> 엘리먼트로 ReactDOM.render()를 호출
// 2. React는 {name: "Miranda" }를 props로 하여 Welcome 컴포넌트를 호출
// 3. Welcome 컴포넌트는 결과적으로 <h1>Hello, Miranda</h1> 엘리먼트를 반환
// 4. React DOM은 <h1>Hello, Miranda</h1> 엘리먼트와 일치하도록 DOM을 업데이트
const element = <Welcome name="Miranda" />;
ReactDOM.render(
element,
document.getElementById('root')
// > "Hello, Miranda"
);
// Welcome을 여러 번 렌더링하는 App Component
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
function App() {
return (
<div>
<Welcome name="Miranda" />
<Welcome name="Stevie" />
<Welcome name="Fanny" />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
// > Hello, Miranda
// > Hello, Stevie
// > Hello, Fanny
※ 참고: extracting-components
: 상위 컴포넌트가 하위 컴포넌트에게 내려주는 properties(속성)데이터
// 상위 컴포넌트(부모)
function Parent() {
return (
// 사용자 정의 컴포넌트
<Child name = "Amy" />
)
}
// 하위 컴포넌트(자식)
function Child(props) {
return (
<h1>Hello, {props.name}</h1>;
)
}
// 상위 컴포넌트(부모)
class App extends React.Component {
render() {
// 사용자 정의 컴포넌트
return <Child value="SOS" />;
}
}
// 하위 컴포넌트(자식)
class Child extends React.Component{
render(){
return <h3>The value passed from parent is {this.props.value}</h3>;
}
}
: 컴포넌트가 갖는 상태; 객체의 형태로 컴포넌트 내에서 보관하고 관리
State is similar to props, but it is private and fully controlled by the component.
1) Class 컴포넌트로 작성되어야 한다.
2) 값을 변경할 때 반드시 setState 메서드를 사용해야 한다.
3) 값이 변경되면, render() 함수가 실행된다.
구분 | Props | State |
---|---|---|
일반 JavaScript 객체 | 일반 JavaScript 객체 | |
고정 값(Immutable) | 변화 가능(Mutable) => setState | |
컴포넌트에 전달(함수 매개변수) | 컴포넌트 안에서 관리(함수 내 선언 변수) | |
부모(상위) 컴포넌트 데이터를 포함 | 컴포넌트의 로컬 데이터를 포함(캡슐화) | |
읽기 전용(read-only) | 읽거나(readable), 쓰는 것(writable) 가능 | |
비동기적(Asynchronous) 변화 가능 |
※ 참고: using-state-correctly
// Wrong
this.state.comment = 'Hello';
// 대신에 setState()를 사용
// Correct
this.setState({comment: 'Hello'});
// this.state를 지정할 수 있는 유일한 공간은 바로 constructor
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
// * 객체보다는 함수를 인자로 사용하는 다른 형태의 setState()를 사용
// 이전 state를 첫 번째 인자로, 업데이트가 적용된 시점의 props를 두 번째 인자로 받는 함수
constructor(props) {
super(props);
this.state = {
posts: [],
comments: []
};
}
// 별도의 setState() 호출로 이러한 변수를 독립적으로 업데이트
componentDidMount() {
fetchPosts().then(response => {
this.setState({
posts: response.posts
});
});
fetchComments().then(response => {
this.setState({
comments: response.comments
});
});
}
⭐️ 하위 component에서 상위 component 데이터 변경하는 법
class App extends React.Component {
constructor(){
super();
this.state = {name :"Miranda Hart"};
}
changeName(){
this.setState({name : "Stevie Sutton"});
}
render(){
return (
<div>
<h3>Hello {this.state.name}</h3>
<button type='button' onClick=this.changeName.bind(this)}>
Save
</button>
</div>
);
}
}
// setState에 매개변수로 객체 전달
// React는 비동기적으로 state에 변화 만든다.
// (전달된 객체의 key값만을 제시된 value 값으로 바꾼다)
// (ref: https://dev.to/blizzerand/react-basics--state-props--functional-components-5cll)