월요일 연휴 맞이 리액트 다시 복습하는 시간 가지기
dom을 직접 건드리는 작업은 번거롭다.
dom을 전부 날려버리고 다시 만들어서 보여주자
매번 이렇게 하게되면 다양한 문제가 발생
메모리게 가상DOM을 만든다.
업데이트가 필요한 부분만 가상DOM으로 수정한다.
그 이후 REACT의 알고리즘을 통해 다른 부분을 감지하여 실제 DOM에 패치 시켜준다.
자바스크립트 런타임인 Node.js 를 기반으로 만들어진 Webpack 과 Babel 같은 도구들을 사용하기 위해서 설치한다.
조금 개선된 버전의 npm, 프로젝트에서 사용되는 라이브러리를 설치하고 해당 라이브러리들의 버전 관리를 하게 될 때 사용한다.
주로 VSCode를 사용한다.
리액트 컴포넌트에서 xml 형식의 값을 반환해는 것이다.
일종의 UI 조각으로 쉽게 재사용 가능하다.
ReactDOM.render(, document.getElementById('root'));
태그는 꼭 닫혀있어야 한다.(Self Closing 태그)
<input />
두 개 이상의 태그는 무조건 하나의 태그
로 감싸져야 한다.
import React from 'react';
import Hello from './Hello';
function App() {
return (
<> //리액트의 Fragment
<Hello />
<div>안녕히계세요</div>
</>
);
}
export default App;
JSX 내부에 자바스크립트 변수를 보여줘야 할 때에는 {}
으로 감싸서 보여준다
import React from 'react';
import Hello from './Hello';
function App() {
const name = 'react';
return (
<>
<Hello />
<div>{name}</div>
</>
);
}
export default App;
)
}
1) JSX에서 인라인 스타일은 객체 형태
로 작성해야한다.
2) background-color처럼 - 로 구분되어 있는 이름들은 backgroundColor처럼 camelCase
형태로 네이밍 해줘야 한다.
3) CSS class 를 설정 할 때에는 class= 가 아닌 className=
으로 설정해야 한다.
import React from 'react';
import Hello from './Hello';
import './App.css';
function App() {
const name = 'react';
const style = {
backgroundColor: 'black',
color: 'aqua',
fontSize: 24, // 기본 단위 px
padding: '1rem' // 다른 단위 사용 시 문자열로 설정
}
return (
<>
<Hello />
<div style={style}>{name}</div>
<div className="gray-box"></div>
</>
);
}
export default App;
JSX 내부의 주석은 {/* 이런 형태로 */}
작성한다.
열리는 태그 내부에서는 // 이런 형태로도
작성 가능하다.
props는 properties의 줄임말로 어떠한 값을 컴포넌트에게 전달해줘햐 할때 사용한다.
//App.js
import React from 'react';
import Hello from './Hello';
function App() {
return (
<Hello name="react" color="red"/>
);
}
export default App;
//Hello.js
import React from 'react';
function Hello({ color, name }){
return <div style={{ color }}안녕하세요 { name }</div>
}
export default Hello;
컴포넌트에 props 를 지정하지 않았을 때 기본적으로 사용 할 값을 설정하고 싶다면 컴포넌트에 defaultProps 라는 값을 설정하면 된다.
//Hello.js
import React from 'react';
function Hello({ color, name }) {
return <div style={{ color }}>안녕하세요 {name}</div>
}
Hello.defaultProps = {
name: '이름없음'
}
export default Hello;
//App.js
import React from 'react';
import Hello from './Hello';
function App() {
return (
<>
<Hello name="react" color="red"/>
<Hello color="pink"/> //'안녕하세요 이름없음'이 핑크색 글씨로 나온다.
</>
);
}
export default App;
컴포넌트 태그 사이에 넣은 값을 조회하고 싶을 땐, props.children 을 조회하면 된다.
//Wrapper.js
import React from 'react';
function Wrapper() {
const style = {
border: '2px solid black',
padding: '16px',
};
return (
<div style={style}>
</div>
)
}
export default Wrapper;
//App.js
import React from 'react';
import Hello from './Hello';
import Wrapper from './Wrapper';
function App() {
return (
<Wrapper>
<Hello name="react" color="red"/>
<Hello color="pink"/>
</Wrapper>
);
}›
export default App;
Wrapper 태그 내부에 Hello 컴포넌트 두개를 넣었는데, 브라우저를 확인하면 다음과 같이 Hello 컴포넌트들은 보여지지 않는다. 내부의 내용이 보여지게 하기 위해서는 Wrapper에서 props.children
을 렌더링해주어야 한다.
//Wrapper.js
import React from 'react';
function Wrapper({ children }) {
const style = {
border: '2px solid black',
padding: '16px',
};
return (
<div style={style}>
{children}
</div>
)
}
export default Wrapper;
조건부 렌더링이란, 특정 조건에 따라 다른 결과물을 렌더링 하는 것을 의미한다.
<div style={{ color }}>
{ isSpecial ? <b>*</b> : null }
안녕하세요 {name}
</div>
<div style={{ color }}>
{isSpecial && <b>*</b>}
안녕하세요 {name}
</div>
&&를 사용하면 첫번째로 나오는 false값을 반환하며 없다면 마지막 값을 반환한다.
리액트에서 엘리먼트에 이벤트를 설정해줄때에는 on이벤트이름={실행하고싶은함수}
형태로 설정해줘야 한다. 이벤트를 설정할 때에는 함수 타입의 값을 넣어주어야 한다.
useState 라는 함수를 사용하면 컴포넌트에서 상태를 관리 할 수 있다.
//App.js
import React from "react";
import Counter from "./Counter";
function App() {
return <Counter />;
}
export default App;
//Counter.js
//useState 함수 불러오가
import React, { useState } from "react";
function Counter() {
//useState를 사용 할 때에는 상태의 기본값을 파라미터로 넣어서 호출.
//함수를 호출하면 배열이 반환.
//첫번째 원소는 현재 상태, 두번째 원소는 Setter 함수.
const [number, setNumber] = useState(0);
const onIncrease = () => {
setNumber(number + 1);
};
const onDecrease = () => {
setNumber(number - 1);
};
return (
<div>
//Setter 함수는 파라미터로 전달 받은 값을 최신 상태로 설정.
<h1>{number}</h1>
<button onClick={onIncrease}>+1</button>
<button onClick={onDecrease}>-1</button>
</div>
);
}
export default Counter;
리액트에서 사용자가 입력 할 수 있는 태그이다.
//App.js
import React from 'react';
import InputSample from './InputSample';
function App() {
return (
<InputSample />
);
}
export default App;
//InputSample.js
import React, { useState } from 'react';
function InputSample() {
const [text, setText] = useState('');
const onChange = (e) => {
//
setText(e.target.value);
};
const onReset = () => {
setText('');
};
return (
<div>
<input onChange={onChange} value={text} />
<button onClick={onReset}>초기화</button>
<div>
<b>값: {text}</b>
</div>
</div>
);
}
export default InputSample;
1) input의 onChange를 사용하면 이벤트 객체 e를 파라미터로 받아올 수 있다.
2) 이 객체의 e.target은 이벤트가 발생한 DOM을 가리킨다.
3) e.target.value
를 조회하면 현재 input의 value값을 알 수 있다.
1) input에 name
을 설정하고 이벤트가 발생했을 때 이 값을 참조하는 것이다.
2) useState에서는 문자열이 아니라 객체 형태의 상태
를 관리해야한다.
//InputSample.js
import React, { useState } from 'react';
function InputSample() {
const [inputs, setInputs] = useState({
name: '',
nickname: ''
});
const { name, nickname } = inputs; // 비구조화 할당을 통해 값 추출
const onChange = (e) => {
const { value, name } = e.target; // 우선 e.target 에서 name 과 value 를 추출
setInputs({
...inputs, // 기존의 input 객체를 복사한 뒤
[name]: value // name 키를 가진 값을 value 로 설정
});
};
const onReset = () => {
setInputs({
name: '',
nickname: '',
})
};
return (
<div>
<input name="name" placeholder="이름" onChange={onChange} value={name} />
<input name="nickname" placeholder="닉네임" onChange={onChange} value={nickname}/>
<button onClick={onReset}>초기화</button>
<div>
<b>값: </b>
{name} ({nickname})
</div>
</div>
);
}
export default InputSample;
1) 리액트에서 객체를 업데이트하게 될 때에는 기존 객체를 직접 수정하면 안되고, 새로운 객체를 만들어서, 새 객체에 변화를 주어야 한다.
setInputs({
...inputs,
[name]: value
});
1) 불변성을 지켜야만 리액트 컴포넌트에서 상태가 업데이트가 됐음을 감지 할 수 있고 이에 따라 필요한 리덴더링이 진행된다.
2) 컴포넌트 업데이트 성능 최적화를 제대로 할 수 있다.
1) 리액트를 사용하는 프로젝트에서도 가끔씩 DOM 을 직접 선택해야 하는 상황이 발생 할 때가 있다(특정 엘리먼트의 크기를 가져와야 한다던지, 스크롤바 위치를 가져오거나 설정해야된다던지, 또는 포커스를 설정해줘야된다던지 등)
2) 그럴 때 useRef
라는 Hook 함수를 사용한다.
import React, { useState, useRef } from 'react';
function InputSample() {
const [inputs, setInputs] = useState({
name: '',
nickname: ''
});
const nameInput = useRef();
const { name, nickname } = inputs; // 비구조화 할당을 통해 값 추출
const onChange = e => {
const { value, name } = e.target; // 우선 e.target 에서 name 과 value 를 추출
setInputs({
...inputs, // 기존의 input 객체를 복사한 뒤
[name]: value // name 키를 가진 값을 value 로 설정
});
};
const onReset = () => {
setInputs({
name: '',
nickname: ''
});
nameInput.current.focus();
}; //input에 포커스를 하는 focus() DOM API를 호출해주었다.
return (
<div>
<input
name="name"
placeholder="이름"
onChange={onChange}
value={name}
ref={nameInput}
/>
<input
name="nickname"
placeholder="닉네임"
onChange={onChange}
value={nickname}
/>
<button onClick={onReset}>초기화</button>
<div>
<b>값: </b>
{name} ({nickname})
</div>
</div>
);
}
export default InputSample;
1) useRef()
를 사용하여 Ref 객체를 만들고,
2) 이 객체를 우리가 선택하고 싶은 DOM
에 ref 값으로 설정해준다.
3) 그러면, Ref 객체의 .current
값은 우리가 원하는 DOM 을 가르키게 됩니다.
동적인 배열을 렌더링해야 할 때에는 자바스크립트 배열의 내장함수 map() 을 사용한다.
1)리액트에서 배열을 렌더링 할 때에는 key 라는 props 를 설정해야 한다. key 값은 각 원소들마다 가지고 있는 고유값으로 설정을 해야한다.
2) Map에 key 값이없다면 중간의 값이 바뀌었을때 그 하위 값들이 전부 변한다. key값을 사용한다면 key를 이용해 중간의 값을 추가하게 된다.
//UserList.js
import React from 'react';
function User({ user }) {
return (
<div>
<b>{user.username}</b> <span>({user.email})</span>
</div>
);
}
function UserList() {
const users = [
{
id: 1,
username: 'velopert',
email: 'public.velopert@gmail.com'
},
{
id: 2,
username: 'tester',
email: 'tester@example.com'
},
{
id: 3,
username: 'liz',
email: 'liz@example.com'
}
];
return (
<div>
{users.map(user => (
<User user={user} key={user.id} />
))}
</div>
);
}
export default UserList;
오늘은 여기까지.. 복습은 이어서 진행할 예정