이제까지는 HTML + CSS + Vanilla (순수) JS 로 공부를 해왔다. 하지만, 최근 웹페이지는 유저와 많은 상호작용이 존재한다.즉 DOM 상태 관리가 필요하다. 이에, 편리한 (Fontend) JavaScript Library를 소개한다. 아래 목차는 공식 문서를 토대로 작성했다. 상세히 읽고 codesandbox에서 실습해보면서 재밌게 공부하였다.
What is React
특징 & 장점
Component ( 하나의 의미를 가진 독립적인 단위 모듈 ) 개념에 집중한다. 어찌보면 Customizing HTML tag를 작성한다는 느낌이 든다. 직관적이고 재사용성이 높아진다. 유저와의 상호작용에 유리하다. state, props 변수를 통해 데이터를 관리한다. View Layer (of MVC application)
Intro. Docs for React
React is javascript library for building user interfaces.
시작하기
$ npx create-react-app project_name
$ cd project_name && npm start // 서버 켜지고, 페이지 오픈
위 명령어를 실행하면 React를 위한 기본적인 파일 구조를 구성해준다. 아직 구체적인 파일 연결은 알지 못하지만 package.json 파일에서 scripts 부분을 살펴보면 "start": "react-scripts start" 지금까지 사용한 node, pm2 와 다른 패키지를 사용해서 결과물을 확인할 수 있다.
2. Introducing JSX
JSX is a syntax extension to JavaScript. Component 를 화면에 표시하기 위함 - babel(= JS Compiler) 이 알아서 변환.
This help to use markup in JavaScript code. It looks like HTML not quite HTML.
JSX 규칙
- 반드시 하나의 엘리먼트로 감싸야한다.
Tip! 무의미한 tag로 감싸히 싫다면?
<React.Fragment /> , 혹은 <> children </> 으로 가능하다. 그리고 curly bracket 없이 배열 [<h1/>, <h2/>] 을 바로 기입하면 spread syntax로 풀려서 이어 붙여진다. - 자바스크립트
코드/변수 (Javascript expression)를 적용할 때는 { } (curly braces) 안에 작성하기
세미콜론 안됨, 안에 함수 실행결과는 괜찮은데, 함수 정의하고 사용은 안됨. IIFE 는 가능하겠다.
객체는 안되고 속성 접근해서 원시타입 변수만 가능한 듯.
배열은 원소 모두 따닥따닥 붙어서 출력되니깐, arr.join('seperator') 사용해서 내가 원하는 대로 붙이기
혹은, 배열 내부에 component 있고 그 배열 자체를 rendering 하면, 소괄호 안 쓰고도 알아서 풀어진다. - JSX 내부에서는 if 문 대신, 삼항 연산자 사용해야함.
- HTML보다 JS에 가깝기 때문에, React DOM 변수명은 camelCase 스타일로 작성됨.
ex ) 엘리먼트의 클래스 이름을 적용시, className 사용하기
JSX Prevents Injection Attacks
Everything is converted to a string before rendering.
XSS (ex Inject script tag)
JSX Presents Objects
React.createElement( ) returns object called "React elements"
3. Rendering Elements
If you wanna create/update an element, use ReactDOM.render()
React only updates what's necessary. (comparing previous one)
4. Components and Props
Component를 통해 Split UI into independent, reusable.
Functional Component (with HOOK) vs Class Component
Class 로 전반적인 구조를 파악하고, Functional 을 공부하는 것을 추천한다.
// functional
function Welcome(){
return <h1> Hello </h1>;
}
// class
class Welcome extends React.Component {
render(){
return <h1> Hello </h1>;
}
}
ReactDOM.render(
<Welcome />,
document.getElementById('root')
)
※ 주의사항 : Tag 명은 대문자로 시작해야함
I wonder className also props ? or for CSS ?
HTML class 속성으로처럼 JSX에서는 className 속성으로 정의할 뿐이다. 이는 props 객체의 속성값으로 저장 되고, 추후 CSS Selector로 사용된다.
Props are Read-Only
it must never modify its own props.
Fragments
React는 tag 하나로 감싼 형태로 element를 Rendering한다. 하지만, table tag 같은 경우 내부에 무의미한 <div> tag가 존재해서는 안된다. 그래서 render 되지 않는 <React.Fragment> 혹은 <></> 와 같은 단축문법 사용 가능하다. 전자는 key 가 유일한 속성이다.
5. State and Lifecycle
인간은 탄생, 삶, 죽음이라는 생애주기를 갖고 있다. React Component 또한 그러하다. 다만 Mounting(탄생), Update(변화), Unmounting(해제) 라는 상황으로 구분되어진다.
Props vs. State
- props
외부로부터 전달받은 값, render 시 사용하는 tag 내부 속성으로 값을 전달한다. - state
내부에서 변화하는 값, constructor 내부에서는 할당이 가능하고, 외부에서는 setState 메소드를 통해 가능하다.
component 내부의 props 혹은 다른 state로 값으로부터 독립적이어야한다.
construcor 정의하지 않은 코드는?
자동으로 super( )가 실행이 되고 this를 사용 가능하다 하지만, 권장하지 않는다. by 출처
Clock 실습
React Lifecycle 이해를 위해 1초 마다 시간이 업데이트되는 함수를 작성해보았다.
function Clock(props){ // JSX 에서 속성을 정의하면 아래에서 dot notation으로 접근 가능.
return (
<div>
<h1>
Time : {props.prop1.toLocaleTimeString()}
</h1>
</div>
)
}
function tick(){
ReactDOM.render(
<Clock prop1={new Date()} />,
document.getElementById('root')
)
}
setInterval(tick, 1000);
Component와 별개로 setInterval 함수를 통해 콜백함수 tick 을 실행하고 있다. 이제는, 컴포넌트 상태 자체가 업데이트되면서 화면을 re-rendering 하는 작업을 진행해보자. 이를 위해 "state" 를 알아야한다.
Converting a Function to a Class
Functional Component를 구현하려면 HOOK 개념을 알아야하므로, 우선 class 방식으로 진행해보자.
class Clock extends React.Component {
constructor(props){
super(props);
// this.props, this.state 는 특별한 변수
this.state = {date: new Date()}; // this.setState() 함수와 연결
}
render(){
return (
<h1>
{this.props.prop1}
<br/>
Time {this.state.date.toLocaleTimeString()}
</h1>
);
}
/* lifecycle methods */
componentDidMount(){ // 필수
this.timerID = setInterval(()=>this.tick(), 1000);
}
componentWillUnmount(){ // 필수
clearInterval(this.timerID);
}
tick(){
this.setState({ // 필수 this.state update
date: new Date()
})
}
}
ReactDOM.render(
<Clock prop1="hello"/>,
document.getElementById('root')
)
아래와 같은 과정으로 상태가 변화하고 re-rendering 한다.
- Component is passed to ReactDOM.render( ), React calls the constructor of the component.
- React calls component's render( ) method to learn what should be displayed on the screen.
- After inserting ouput in the DOM, React calls the componentDidMount() lifecycle method. It has this.setState method( ) which reports the state has changed. So React calls the render() again.
- If component is ever removed from the DOM, React calls the componentWillUnmount( )
More about setState( ) method
states is called local or encapsulated.
- After initializing this.state in constructor(), we can modify this.state only with this.setState method.
constructor(props){
super(props);
this.state = {counter: 1};
}
this.setState(function(prevState, props) {
return {
counter: prevState.counter + 1
}
});
- State Updates are Merged
we can update the state object partially.
The Data Flows Down
top-down (unidirectional) data flow.
서로 다른 컴포넌트가 공통 상태를 가지고 있다면, 상위 객체로 묶어 상태를 한번에 저장한다. 이는 React 스러운 프로그래밍 방식이다. 혹여 하위 객체에서 상위 상태를 바꿔야한다면, props를 통해 건내받은 eventHandler를 이용하자.
Counters which are starting from different number.
6. Handling Events
- event.preventDefault() 호출 하는 이유 : 고민 중
- handler.bind(this) 하는 이유 : 안하면 this === 전역객체
Tip! 화살표 함수로 선언하면 안해줘도 된다.
아래 코드는 버튼을 클릭하면 콘솔창에 "clicked" 가 출력되는 event handler 를 연결해 주었다.
// /* React Syntax */
// functional
function Button(){
function handler(event){
event.preventDefault(); // simple call
console.log("clicked");
}
return (
<button onClick={handler}>
Active!
</button>
)
}
// class
class Button extends React.Component {
constructor(props){
super(props);
//this.state = {}; //생략
this.handler = this.handler.bind(this);
}
handler(event){
event.preventDefault(); // simple call
console.log("clicked");
}
render(){
return (
<button onClick={this.handler}>
Active!
</button>
)
}
}
ReactDOM.render(
<Button />, document.getElementById('root')
)
7. Conditional Rendering
분기 가능!
function SayHello(props){
return <h1>Hello</h1>;
}
function SayHi(props){
return <h1>Hi</h1>;
}
function Greeting(props){
if (props.toggle){
return <SayHello />;
}
return <SayHi />;
}
ReactDOM.render(
<Greeting toggle={false}/>,
document.getElementById('root')
)
Element Variables
Login/ Logout example
function LoginButton(props) {
return (
<button onClick={props.onClick}>
Login
</button>
);
}
function LogoutButton(props) {
return (
<button onClick={props.onClick}>
Logout
</button>
);
}
class LoginControl extends React.Component {
constructor(props) {
super(props);
/*button이 아니라 이 class에 binding 되도록 하는 듯*/
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>
{button}
</div>
);
}
}
ReactDOM.render(
<LoginControl />,
document.getElementById('root')
);
Inline If with Logical && Operator
const element = (
<div> do you want to put this?
{ true && <h1> this code is put in </h1> }
{ false && <h1> ignore </h1> }
</div>
)
ReactDOM.render(element, document.getElementById('root'))
Inline If-Else with conditional Operator - 3항 연산자
function Element(props){
const toggle = false;
return (
<div>
{ toggle ? "true" : "false"}
</div>
);
}
ReactDOM.render(<Element/>, document.getElementById('root'))
8. Lists and Keys
arr.map() 으로 쉽게 element tag 생성하면 됨.
const members = ['kim', 'park', 'seo'];
const eleList = members.map((member) => <li>{member}</li>);
ReactDOM.render(<ul>{eleList}</ul>, document.getElementById('root'));
Keys
keys help React identify items in list (so keys must only be unique among siblings).
index keys is highly discouraged.
출력은 잘되어도 발생하는 경고는 무엇이지? 각 item key 설정하라고 권고하는 듯.
9. Forms
Controlled Components
form elements : <input>, <textarea>, and <select>
they maintain thier own sate and update it based on user input with setState() method.
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>
);
}
}
handleChange runs on every keystroke to update the React state.
그러므로 input이 여러개이고, 같은 handler를 binding 하고 있다면, 아래 키워드를 검색해보시오.
[Computed property names] for setState 참고하기 (내거 블로그 연결하기)
textarea Tag
this element defines its text by its children : so, uses value attribute instead.
After input written, state changes by handler. and React render again <textarea> by new state.
select tag
For selected attribute, React, uses a value attribute on the root <select>
Handling Multiple Inputs
11. Composition vs Inheritance
Containment
Anything inside wrapper element is children- by nesting(중첩) components pass arbitrary children.- component 대신 text 일 수도
Inheritance with props
props include primitive values(reference 도 되는데..), React elements, or functions
Hooks
함수 컴포넌트에서도 state 사용 가능 : React 16.8 버전 이후에 Hooks 도입
const [value, setValue] = useState('');
// 왼쪽 value는 현재 상태
// 오른쪽은 상태 업데이트 함수
'1️⃣ 개발 지식 A+ > FE' 카테고리의 다른 글
how to show cookie headers at client (0) | 2021.01.20 |
---|---|
[반응형 웹] #1. 미디어 쿼리 (0) | 2021.01.09 |
webpack 환경 설정 (0) | 2021.01.09 |
[JS] 비동기 동작 스케줄링 방법 3가지 (0) | 2020.12.22 |
[JS] 객체 지향 프로그램 (0) | 2020.12.10 |