React 소개
- 페이스북에서 2013년 5월에 오픈 소스로 공개됨.
- 반응형 프로그래밍.
- 컴포넌트(재사용이 가능한 독립적인 객체)의 조합으로 View를 구성함.
- Virtual Dom으로 필요한 부분만 한 번에 렌더링 하기 때문에 성능 최적화에 강함 → 편리함.
처음엔 컴포넌트만 생각해보기!
재사용성과 확장성을 처음부터 생각하는 것은 어려움. 눈에 보이는 UL를 컴포넌트로 구현하는 것에 집중하기.
create-react-app, JSX
- create-react-app : 리액트를 만들기 위한 가장 빠른 방법.
npm init react-app my-app
- src/App.js는 가장 기본이 되는 js 파일임. App 함수 내 가상 돔을 JSX라 부름.
- class 대신 className을 사용.
npm start
를 통해 실행할 수 있음(루트에 package.json의 scripts 영역에서 확인 가능).{}
를 사용하여 데이터를 다룸.
컴포넌트
- 리액트 컴포넌트는 html, 로직, 스타일 정보를 담음.
- 상태와 이벤트를 가짐.
- 트리구조로 이루어져 서로 데이터와 메시지를 주고 받을 수 있음. 이때 데이터는 위에서 아래로 흐르기 때문에 단방향임.
import logo from "./logo.svg"; import propTypes from "prop-types"; function Logo({ size = 200 }) { return ( <img src={logo} className="App-logo" alt="logo" style={{ width: size, height: size }} /> ); } Logo.propTypes = { //size:propTypes.node.isRequired를 통해 props 입력을 강제할 수 있음. size: propTypes.number, }; export default Logo;
import "./App.css"; import Logo from "./components/Logo"; function App() { return ( <div className="App"> <header className="App-header"> <Logo size={100} /> <Logo /> </header> </div> ); } export default App;
어떻게 재사용 가능한 컴포넌트를 만들까?
- UI를 추상적으로 바라보고 공통점 찾기.
- 다른 동료가 어떤 컴포넌트인지 모를 정도로 쪼개면 안됨.
- 점차적으로 규칙 정하기. ex) 도메인으로 분류, 역할로 분류, 크기로 분류
- 정하는 것은 팀, 모두의 의견 존중하기.
상태와 이벤트 바인딩
Counter 만들기
import { useState } from "react"; import PropTypes from "prop-types"; function Counter({ onIncrease, onDecrease }) { const [count, setCount] = useState(0); const increaseCounter = () => { setCount(count + 1); if (onIncrease) onIncrease(count + 1); }; const decreaseCounter = () => { setCount(count - 1); if (onDecrease) onDecrease(count - 1); }; return ( <div> <span>{count}</span> <button onClick={increaseCounter}>+</button> <button onClick={decreaseCounter}>-</button> </div> ); } Counter.propTypes = { onIncrease: PropTypes.func, onDecrease: PropTypes.func, }; export default Counter;
import { useState } from "react"; import Counter from "./components/Counter"; function App() { const [totalCount, setTotalCount] = useState(0); return ( <div> totalCount : {totalCount} <Counter onIncrease={(count) => setTotalCount(totalCount + 1)} onDecrease={(count) => setTotalCount(totalCount - 1)} /> <Counter onIncrease={(count) => setTotalCount(totalCount + 1)} onDecrease={(count) => setTotalCount(totalCount - 1)} /> <Counter onIncrease={(count) => setTotalCount(totalCount + 1)} onDecrease={(count) => setTotalCount(totalCount - 1)} /> </div> ); } export default App;
useState
를 통해 지역 상태를 관리할 수 있음.
- 실행될 함수를 선언해
onClick
이란 이벤트 바인딩을 통해 함수를 실행시킴.
- 부모 컴포넌트에서 props를 통해 메시지를 받을 수 있도록 함수를 전달할 수 있음.
useEffect
- 무언가 변화가 있을 때 감지하여 반응하는 Hook
// count의 변화를 감지. useEffect(() => { document.title = `You clicked ${count} times`; }, [count]); // 컴포넌트가 처음 로드될 때 실행됨. useEffect(() => { const handleScroll = () => { console.log(window.scrollY); } document.addEventListener("scroll", handleScroll()); //전역적인 이벤트 사용할 때 쓸 수 있음. return () => document.removeEventListener("scroll", handleScroll); //return으로 변환한 함수는 컴포넌트가 제거될 때 실행됨. }, []);
useRef
- DOM에 직접 접근할 때 사용함.
- 지역 변수로 사용할 때 사용함.
- useState는 값이 변경될 때 다시 렌더링 되지만 useRef는 값이 변경돼도 다시 렌더링하지 않음.
function TextInputWithFocusButton() { const inputEl = useRef(null); const onButtonClick = () => { // `current` points to the mounted text input element inputEl.current.focus(); }; return ( <> <input ref={inputEl} type="text" /> <button onClick={onButtonClick}>Focus the input</button> </> ); }