사용자와의 interaction이 많은 앱은 DOM의 여러 가지 상태를 좀 더 효율적으로 관리하고 기능 개발에만 집중할 수 있도록 React와 같은 프론트엔드 라이브러리 혹은 프레임워크를 사용한다.
const element = <h1>Hello, world</h1>;
ReactDOM.render(element, document.getElementById('root'));
JSX란 React의 component를 화면에 보여주기 위해 사용하는 JavaScript 확장 문법이다. 형태상 HTML과 JavaScript 문법과 흡사한 면이 많다. JSX 표현은 Babel과 같은 컴파일러 소프트웨어를 이용해 JavaScript로 해석된다.
const element = (
<h1 className="greeting">
Hello, world!
</h1>
); // JSX를 이용해 작성된 React element
ReactDOM.render(element, document.getElementById('root')); // React element를 DOM에 render
위의 코드는 아래의 코드와 같다.
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
ReactDOM.render(element, document.getElementById('root'));
두 번째 코드 예시와 같이 React.createElements
등과 같은 method를 사용하여 JSX 없이 React를 사용할 수도 있으나, 복잡도가 높고 가독성이 낮아 선호하지 않는다.
const name = 'Ha Young';
const hello = (
<h1 className="greeting">
Hello, {name}! // DOM에 "Hello, Ha Young"으로 render
</h1>
)
function Mailbox(props) {
const unreadMessages = props.unreadMessages;
return (
<div>
<h1>Hello!</h1>
{unreadMessages.length > 0 &&
<h2>
You have {unreadMessages.length} unread messages.
</h2>
} // unreadMessages가 0개일 경우 h2 태그는 render 되지 않는다
</div>
);
}
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
{isLoggedIn
? <LogoutButton onClick={this.handleLogoutClick} />
: <LoginButton onClick={this.handleLoginClick} />
}
</div>
);
}
class
가 아닌 className
을 사용한다.function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
return (
<ul>{listItems}</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
목록을 render할 때에는 목록의 항목마다 고유한 key를 주는 것이 권장된다.
React에서 component란 하나의 의미를 가진 독립적인 단위 모듈을 말한다. 내가 직접 customize할 수 있는 고유 HTML tag라고 표현할 수도 있다. 개발하는 앱에 따라 필요한 기능을 만들어 구성할 수 있기에 재사용성이 높고 직관적이다.
properties의 줄임인 props는 하나의 component안에서 접근 가능한 attribute들을 말한다.
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
const element = <Welcome name="Sara" />;
ReactDOM.render(
element,
document.getElementById('root')
);
위의 코드에서 element
변수는 "Sara" 라는 name
props를 가진 Welcome
component의 한 instance이다. 이 경우 화면에는 props.name
값이 "Sara"로 대체된 "Hello, Sara"라는 h1 element가 render된다.
State란, component의 lifecycle 안에서 변화할 수 있는 속성을 말한다. state를 사용하는 component로 만드려면 ES6 문법의 class의 형태와 흡사한 class component로 만들어 주어야 한다. 이후 constructor method 내부에서 this.state
로 state를 정의해 줄 수 있다. Constructor 외부에서 state를 수정할 경우 직접 재할당하거나 push
등의 method를 사용하여 수정해 주지 않고 아래와 같이 this.setState
를 사용한다.
this.setState(prevState => ({
...prevState,
thingToAdd
});
OR
this.setState({newState});
function Clock(props) {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {props.date.toLocaleTimeString()}.</h2>
</div>
);
}
function tick() {
ReactDOM.render(
<Clock date={new Date()} />,
document.getElementById('root')
);
}
setInterval(tick, 1000);
인자로 props를 받고, JSX를 return한다. 위에서 상속받지 않는 props는 instance 생성 시 넘겨 준다.
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
this.tick = this.tick.bind(this);
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
super(props)
로 전달해 준다.)render()
라는 method의 return값으로 준다.this.handleClick = this.handleClick.bind(this);
등과 같이 this binding을 해 주어야 한다.
Class component의 경우 component lifecycle 내에서 특정 순간에 쓰이는 내장 lifecycle method가 있다. Lifecycle event가 발생할 때마다 해당 method가 불리고, React DOM이 다시 render 된다.
componentDidMount()
componentDidUpdate()
componentWillUnmount()
React에서는 웹 어플리케이션을 만들 때 가장 하위의 component부터 설계해 나가는 bottom-up 방식으로 접근한다. 보통 다음과 같은 절차로 설계한다.
React에서는 항상 데이터가 아래로 흐른다면, 하위 component에서 상위 component에 위치한 state에 영향을 주어야 할 때 문제가 생긴다. 이를 해결하기 위한 개념이 lifting state up으로, 콜백의 형태로 하위 component에 상태를 변경시키는 함수를 전달하는 방식으로 접근한다.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
tasks: ["do laundry", "go grocery shopping", "study react"]
};
this.setTodos = this.setTodos.bind(this);
}
setTodos(newTask) {
this.setState(prevState => {
...prevState,
newTask
});
}
render() {
const todos = this.state.tasks
return (
<>
<TodoCount todos={todos} />
<TodoList todos={todos} />
<AddTodo setTodos={setTodos} />
</>
);
}
}
function AddTodo({ setTodos }) {
function handleSubmit(event) {
event.preventDefault();
const todo = event.target.elements.todo.value;
setTodos(todo);
}
return (
<form onSubmit={handleSubmit}>
<input type="text" id="todo" />
<button type="submit">Add Todo</button>
</form>
);
}
위의 코드에서 AddTodo라는 component는 App의 하위 component로, 이 곳에서 submit event가 발생하면 App의 this.state.tasks
목록에 새로운 할 일을 추가해야 한다. App의 setTodos()
method를 AddTodo에 전달해, AddTodo의 handleSubmit()
event handler에서 setTodos를 호출하는 형식으로 해결한다.
npx create-react-app my-app
cd my-app
npm start
Create React App 패키지를 통해 간단하게 React를 기반으로 한 프로젝트를 jump-start할 수 있다. 위의 코드를 실행하면 my-app
이라는 디렉토리에 boilerplate code로 이루어진 새로운 프로젝트가 생성된다.
https://reactjs.org/docs/
https://www.freecodecamp.org/news/what-is-lifting-state-up-in-react/