1. What I learned today
라이브러리 vs 프레임워크
- 라이브러리 : 개발 편의를 위한 도구 모음 (공구)
- 프레임워크 : 도구의 모음과 기반 구조까지 포함한 개념 (공장)
- 리액트는 자유도가 높은 프레임워크이다.
React에서 DOM (문서 객체 모델) 와 Element 생성
- Document Object Model : 문서의 논리 트리 표현
react document cdn을 통해 바닐라 js에 react 문법을 주입하여 사용
createElement(tag, props, children)로 생성하여 render 함수로 화면에 표시한다.
JSX
React.createElement 표현식.
unpkg를 통해 babel을 가져오면 변수에 html 문법을 삽입해도 동작하는 코드가 될 수 있다. (html ↔ js)
멀티 Element
element의 children에 여러 개를 삽입할 수 있다.
- 만약
element를 생성하지 않고 원래 존재하는 태그에 자식을 여러개 삽입할 경우 React.Fragment를 사용한다. (빈 태그도 가능)
Element 찍어내기
element 를 함수화하여 만들어 놓고 여러 번 호출 하게 되면 같은 형식에 대해 매번 작성할 필요가 없다. (재사용 가능한 Element)
const Paint = ((title, description)) => {
return (
<>
<h1>{title}</h1>
<h3>{description}</h3>
</>
);
};
const element = (
<>
<Paint title="Good" decription="good"/>
<Paint title="Bad" decription="bad"/>
</>
);
ReactDOM.render(element, rootElement);
JS와 JSX. 섞어쓰기
- JSX로 html 구조로 사용하는 코드를 JS 문법으로 제어할 수 있다.
const text ({text}) => {
if (text.charAt(0) === text.charAt(0).toUpperCase()){
return <h1>{text}</h1>
}else{
return <h3>{text}</h3>
}
};
리랜더링
- 바닐라 JS : 변경으로 인해
element를 다시 그린다.
- React : 변경된 부분만 다시 렌더링한다.
- 리액트에서 Element는 불변 객체이지만 변경된 화면을 렌더링 할 수 있는 이유는
ReactDOM.render 함수로 새로운 element 전달하면 변경된 부분을 재조정하여 변경하는 과정을 리액트가 한다.
element의 타입이 변경될 시 이전 element를 버리고 새로 그리고, 타입이 같다면 key → props 순으로 비교하여 변경사항 반영 (Virtual DOM 사용)
이벤트 핸들러
- React 이벤트 핸들러 :
on{Event} onClick, onMouseOut, onFocus, onBlur ...
<script
crossorigin
src="https://unpkg.com/react@18/umd/react.development.js"
></script>
<script
crossorigin
src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"
></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<div id="root"></div>
<script type="text/babel">
const rootElement = document.getElementById("root");
const state = { keyword: "", typing: false, result: "" };
const App = () => {
function handleChange(event) {
setState({ keyword: event.target.value, typing: true });
}
function handleClick() {
setState({
typing: false,
result: `we find result of ${state.keyword}`
});
}
return (
<>
<input onChange={handleChange} />
<button onClick={handleClick}>search</button>
<p>
{state.typing ? `Looking for ${state.keyword}...` : state.result}
</p>
</>
);
};
function setState(newState) {
Object.assign(state, newState);
render();
}
function render() {
ReactDOM.render(<App />, rootElement);
}
render();
</script>
컴포넌트 상태 다루기
- 컴포넌트 : element(요소)의 집합
- useState : 컴포넌트의 상태 관리 훅
React.useState(초기화 데이터) 형식으로 사용할 수 있고 반환은 [ value, set ] 로 가능하다.
useState 의 매개변수로 함수를 전달하여 lazy initialize 하게 동작할 수 있다.
const App = () => {
const [keyword, setKeyword] = React.useState("");
const [typing, setTyping] = React.useState(false);
const [result, setResult] = React.useState("");
function handleChange(event) {
setKeyword(event.target.value);
setTyping(true);
}
function handleClick() {
setTyping(false);
setResult(`we find result of ${keyword}`);
}
return (
<>
<input onChange={handleChange} />
<button onClick={handleClick}>search</button>
<p>{typing ? `Looking for ... ${keyword}...` : result}</p>
</>
);
};
- useEffect : (부수)효과를 제어 (dependency array)하는 훅
- ex )
keyword가 변경될 때 useEffect 내 함수를 실행시키는 효과 (컴포넌트가 그려지는 그 순간만 동작할 수 있도록 제한할 수 있다.
커스텀 훅 만들기
useState,useEffect 와 같은 함수를 비슷한 작동을 하더라도 분리해야 하는 경우 하나로 합친 커스텀 훅을 통해 코드를 간결하게 작성할 수 있다.
function useLocalStorage(itemName, value = "") {
const [state, setState] = React.useState(() => {
return window.localStorage.getItem(itemName) || value;
}, [state]);
React.useEffect(() => {
window.localStorage.setItem(itemName, state);
}, [state]);
return [state, setState];
}
Hook Flow
- hook들의 호출 타이밍.
useState의 set은 인자로 prev (전 값)을 가져온다.
useEffect에서 deps가 존재할 때 변경되지 않았다면 호출되지 않는다.
render 이후에 useEffect가 실행된다,
- App render → child render → child effect → App effect 순으로 호출 된다.
Element 스타일 입히기
css에서 스타일을 적용할 때 리액트에서는 className과 같이 분류하여 적용할 수 있는데 JSX 문법으로 함수를 이용하여 공통적으로 갖는 className의 앞 부분을 지정하고 각 요소에 적용할 수 있다.
className은 문자열, style props는 객체이다. 카멜 케이스이고, style이 먼저 적용된다.
function Button({className="", color style, ...rest}){
return (
<button
className={`button ${className}`}
style={{fontSize:50, ...style}}
{...rest}
/>
);
}
const element = (
<>
<Button style={{borderRadius: "50%"}}>Green</Button>
</>
);
ReactDOM.render(element, document.getElementById("root");
Ref로 DOM 다루기
useRef를 사용하여 최적의 방법으로 element에 대해 접근한다.
const inputRef = React.useRef();
const App = () => {
React.useEffect(() => {
inputRef.current.focus();
}, []);
return (
<>
<input ref={inputRef} />
<div style={{height: 100, width: 300, backgroundColor: "brown"}}
</>
);
};
- 기본적으로 JSX를 이용하여 HTML의 구조로 사용할 수 있다. (장점)
<label htmlFor=""/>을 사용하는 것을 권장하고 가변적인 value라면 defaultValue 속성을 갖는 것을 권장한다.
- Form 내의 요소들을 관리하는 것은
console.dir()을 통해 확인할 수 있고, id 속성 값으로 event 객체에서 값들을 선택하여 추출 할 수 있다.
- 기본 동작을 삭제하고 react로 제어하고자 한다면
event.preventDefault()를 사용한다.
- 한 번 더 봐야할 것 같다. (Form 다루기 2)
Error 다루기
class ErrorBoundary extends React.component {
state = {error: null};
static getDerivedStateFromError(error) {
return { error };
}
render() {
const { error } = this.state;
if (error) {
return <p>There is some error...</p>
}
return this.props.children;
}
}
- 클래스 컴포넌트로 리액트에서 컴포넌트가 아예 그릴 수 없을 때
try catch 방식으로 에러를 핸들링 할 수 있다.
Fallback을 설정하여 에러 발생 시 보여줄 컴포넌트를 설정한다.
Key와 리랜더링
key 란 value 를 특정하는 이름이다.
- 특정
value 를 화면에 표현, 삭제 하더라도 key 로 다시 원본 값에 접근하여 다시 보여지게 만들경우 값의 변경이 아닌 컴포넌트를 재사용하기 때문에 focus를 준 버튼이 그대로 따라다닌다. (효율적인 동작)
2. Code Snippets
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>