터미널에서 "$ npm start" 혹은 "$ yarn start"와 같은 명령어를 사용해서 React 앱을 구동시키면, 이 도구는 src 폴더에서 index.js
라는 파일을 찾고, 거기에 적혀있는 코드대로 동작하게 된다.
index.js
파일 오픈 시, < App / > 이라는 코드를 찾을 수 있는데, 이 코드를 삭제할 경우 Default UI도 함께 삭제되는 것을 알 수 있다.
< App / > 은 App.js
로부터 온 태그이고, App.js
에 있는 함수에서 Return되는 부분이 화면에 그려지는 UI인 것이다.
즉, index.js
파일은 입구의 역할을 하는 것이다.
index.js
파일엔 전역적인 설정이 들어가있고, 그 중 App.js
함수에서 리턴되는 부분을 이용해 하나의 서비스를 제작할 수 있는 것!
그렇다면 index.js
파일에 있는 < id="root" > 인 부분은 어디서 왔을까?
index.html
파일을 보면, App 태그가 있는 부분에 ID Value가 "root"인 태그로 렌더링되라는 코드가 있다.ReactDOM.render (
//ReactDOM 파악 시, 렌더링 해라
<React.StrictMode>
<App />
// App 컴포넌트에 있는 내용을,
</React.StrictMode>,
document.getElementById('root')
// document에 있는 id값이 root인 요소 안에
Id값이 root인 요소는 public directory라는 폴더에 있는 index.html
파일에 있다.
해당 파일에서 "root"는 index.html
에 있는 div 태그인데, React는 기본적으로 이 div 구역 안에 다양한 코드를 추가해서 화면에 출력하는 것이다.
서비스를 배포한다면 배포하기에 가장 최적화된 배포본을 만들어서 배포를 해야한다.
이 작업을 "빌드 (Build)"라고 한다
$ npm run build
라는 코드를 터미널에 사용 시, Build라는 폴더가 생긴다
index.html
과 같이 태그들 사이에 인덴트나 공백이 없는 파일이 있다. 빌드 명령 실행 시, 빌드 결과물을 서비스하게 되는데, 이때 serve
라는 앱을 사용하기를 REACT에선 권장하고 있다.
serve
는 웹서버이고, 해당 웹서버의 옵션 중 "-s"라는 옵션을 주게되면, 사용자는 어떤 경로로 들어와도 index.html
파일로 이동하게 된다.
이때 경로에 build를 추가하면, 사용자가 이동하게 될 index.html
파일은 Build 폴더에 있는 최적화된 파일이다.
REACT는 "사용자 정의 태그를 만드는 기술"이고, 이것이 REACT의 본질이다
복잡한 코드를 하나의 태그로 이름을 붙여서 사용자 정의 태그를 만드는 것이다.
사용자 정의 태그는 함수를 선언해서 만든다. 함수 생성 시, 함수의 이름은 대문자로 시작해야 한다. (ex. function Header() {}
)
만들어진 함수가 리턴하는 내용은 html의 태그들이다.
기본적으로 함수이기 때문에, 사용자 정의 태그들은 재사용성이 매우 뛰어나다.
만들어진 함수를 다른 함수에 html 태그 형식으로 추가하면, 사용자 정의 태그의 내용이 그대로 그려진다.
function Header(){
// 3. App() 안에 모든 코드를 넣지 않고, 코드의 일정 부분을 따로 뺄 수 있다.
// 이 따로 뺀 코드를 담고 있는 함수가 사용자 정의 태그로 사용되는 함수이다.
return (
<header>
<h1><a href="/">WEB</a></h1>
</header>
)
}
function App() { // 1. 리액트에서 기본으로 제공하는 함수
return (
<div> // 2. 리턴되는 부분이 웹페이지에 그려지는 UI다.
<Header></Header>
// 4. 위에 함수로써 빠졌던 부분을 태그로 만들어서 사용하고 있다.
// Header()가 리턴하는 html 태그가 화면에 문제없이 그려진다.
<Header></Header>
// 5. 만들어진 사용자 정의 태그는 재사용성이 뛰어나다.
<Header></Header>
// 6. 이때 Header() 내용이 바뀐다면, App() 안에 있는 태그들의 내용도 자동적으로 일괄 수정된다.
</div>
);
}
React에선 사용자 정의 함수를 "컴포넌트 (Component)"라고 부른다.
컴포넌트를 사용할 경우, 코드의 복잡도가 낮아지는 장점이 추가된다.
일괄 수정이 가능하기 때문에, 유지보수 측면에도 편리성이 크다.
컴포넌트는 일종의 부품이기 때문에, 외부에 공유하고, 공유받을 수 있다.
React는 컴포넌트에 속성을 줄 때, props
라는 단어에 담아서 전달한다.
props
는 그냥 이름이기 때문에 아무 이름이나 사용해도 된다. props
인 것.컴포넌트로 빼놓은 함수의 내용을 직접 수정하지 않고, 해당 함수를 태그로서 갖고 있는 메인 함수에서 해당 태그에 속성을 props
를 통해 부여함으로서, 리턴되는 값을 바꿀 수 있다.
function Header(props) {
// 2. <Header> 태그에 해당하는 함수의 첫번째 매개변수로 props를 주고
console.log('props',props);
// 3. props에 어떤 내용이 있는지 콘솔에서 확인하면
// props 라는 객체의 title은 "React"라는 것을 확인할 수 있다.
// 그리고 props라는 객체가 갖고 있는 요소는 매우 많다. title은 그 중 하나일 뿐
// title에서 "react"라는 값만 출력하고 싶다면, console.log('props', props, props.title) 이라고 했을 때 값만 출력할 수 있다.
return (
<header>
<h1><a href="/">{props.title}</a></h1>
// 4. return 값에 들어가는 구문에 {}을 이용해서 텍스트를 전달하면, 표현식으로 해석되기 때문에 props에서 추출한 값인 "React"가 출력된다.
</header>
)
}
function App() {
return (
<div>
<Header title="React"></Header>
// 1. 태그를 사용하는 함수에서 해당 태그의 title에 "React"라는 값을 준다면:
<Header title="리액트"></Header>
// 5. 동일한 <Header> 태그를 사용하지만, 해당 태그가 props로 전달받는 값은 "리액트"이다.
// 그래서 최종 출력되는 값은 "React"라고 쓰여진 h1 태그와 "리액트"라고 적혀진 h1
// 각각 다른 값을 가진 h1 태그가 2개 생성되는 것.
</div>
);
}
함수 내부에 있는 태그에 props를 주입했을 때, 외부 컴포넌트의 리턴 값들이 주입되는 props의 값에 따라서 자동적으로 생성된다면?
어떤 내용을 props로 줬을 때 내가 구현하고자 하는 부분이 자동 생산이 될 수 있을지 생각해야 한다.
function Nav(props) {
// 3. App()에서 topics라는 이름으로 전달하는 배열을 props를 이용해서 옮겨 받는다.
const lis = []
// 4. topics에 들어있는 요소가 여러개기 때문에 빈 배열을 생성하고,
for(let i = 0; i <props.topics.length; i++){
// 5. 반복문을 돌려서 props로 받은 topics의 길이만큼 안에 있는 요소를 모두 확인한 후에,
let t = props.topics[i];
// 6. props로 받은 topics의 특정 요소인 [i]를 t라는 변수에 담는다.
lis.push(<li key={t.id}><a href={'/read/'+t.id}>{t.title}</a></li>
// 7. 비어있던 배열 lis에 <li></li>를 추가한다.
// 8. <li>의 제목을 동적으로 구성하기 위해 App()으로부터 받은 props 중 title을 {} 안에 추가한다.
// 8-1. props로 받은 topics의 특정 요소는 t라는 변수에 담겨있기 때문에, title이라는 topics의 특정 요소는 t.title로 접근할 수 있다.
// 9. <li>는 기본적으로 링크의 역할을 할 의도로 작성되었기 때문에 <a> 태그를 갖고 있다.
// 9-1. <a> 태그에서 href 속성을 통해 페이지를 이동하는데, 이때 각 <li> 마다 이동하는 고유 경로를 만들어야 한다.
// 9-2. 고유 경로를 동적으로 구성하기 위해 각 <li>의 고유값이 될 id를 경로에 심고 {} 안에 추가한다.
// 9-3. id 또한 props로 받은 topics의 특정 요소는 t라는 변수에 담겨있기 때문에, id라는 topics의 특정 요소를 t.id로 지정된다.
// 10. 각 <li>는 App()의 자식 객체이다.
// 10-1. 자식 객체는 고유 키값이 지정되어야 하기 때문에, 각 <li>마다 키(key)라는 고유값을 가진 프롭이 부여되야 한다.
// 10-2. key라는 prop에 id를 부여한다. (보통 id값을 unique값으로 사용한다.)
return (
<nav>
<ol>
{lis}
// 그리고 완성된 배열 lis를 넣는다. 자바스크립트의 내용을 html 부분에 넣을 땐 {}사용 필수
/*
<li><a href='/read/1'>html</a></li>
<li><a href='/read/2'>css</a></li>
<li><a href='/read/3'>javascript</a></li>
*/
</ol>
</nav>
function App() {
const topics = [
{id:1, title:'html', body: 'html is...'},
{id:2, title:'css', body: 'css is...'},
{id:3, title:'javascript', body: 'javascript is...'}
]
// 2. topics라는 상수 안에 배열을 만들고, <Nav> 안에 들어갈 카테고리들의 정보를 객체로 정리한 다음 배열에 집어넣는다.
// 2-1. 각각의 카테고리는 id라는 고유값을 갖는다.
return (
<div>
<Nav topics = {topics}/>
// 1. <Nav>에 들어갈 카테고리는 각각 카테고리의 이름과 상세페이지의 내용이 들어갈 것이다.
// 1-1. 이 <Nav>라는 컴포넌트에 카테고리를 여러개 만들고 싶다고 가정했을 때,
</div>
)
}
리액트는 자동으로 생성하는 태그의 경우에는 리액트가 이 태그들을 추적해야 한다.
태그를 추적할 때 근거가 필요한데, 이 근거로서 key라는 약속된 prop을 자동 생성하는 태그에 부여한다.
리액트가 추적할 수 있도록 key라는 prop을 추가함으로서, 리액트의 성능을 높이고 리액트가 정확한 동작을 하는 것에 협조할 수 있다.
function Header(props){
return <header>
<h1><a href="/" onClick={(event)=>{
// 2. <a> 에 onClick이라는 이벤트를 건다. 리액트에 있는 html 태그는 유사 html태그기 때문에, 문법이 다르다. (카멜케이스와 중활호 사용)
// 2-1. onClick의 콜백 함수로 들어가는 함수가 호출될 때, event라는 객체를 콜백함수의 첫번째 매개변수로 준다.
// 2-2. 이벤트 객체는 이벤트 상황을 제어할 수 있는 여러 기능이 있다.
event.preventDefault();
// 3. 그 중, 기본적으로 제공하는 <a> 클릭 시 이동하는 것과 같은 기본 이벤트를 방지할 수도 있다.
// 3-1. <a> 태그의 기본 동작을 방지할 경우, 클릭해도 reload가 일어나지 않는다.
props.onChangeMode();
// 4. 기본 이벤트가 방지되었을 때 비로소 App()에서 <Head>에서 props로 전달한 onChangeMode가 가르키는 함수를 호출할 수 있다.
// 4-1. props로 onChangeMode를 가르키고, ()를 이용해서 함수를 실행하는 것이다.
}}>{props.title}</a></h1>
</header>
}
function App() {
const topics = [
{id:1, title:'html', body:'html is ...'},
{id:2, title:'css', body:'css is ...'},
{id:3, title:'javascript', body:'javascript is ...'}
]
return (
<div>
<Header title="WEB" onChangeMode={()=>{
alert('Header');
}}></Header>
// 1. <Header> 링크를 클릭할 때 실행되는 함수를 만든다.
<Nav topics={topics} onChangeMode={(id)=>{
alert(id);
}}></Nav>
</div>
);
}
function Nav(props){
const lis = []
for(let i=0; i<props.topics.length; i++){
let t = props.topics[i];
lis.push(<li key={t.id}>
<a id={t.id} href={'/read/'+t.id} onClick={event=>{
// 3. 링크 클릭 시 경고창이 뜨도록 하기 위해서 <a> 태그에 onClick 이벤트를 추가한다.
// 3-1. onClick 이벤트가 일어날 때 이벤트가 감지되도록 첫번째 매개변수로 event를 준다.
event.preventDefault();
// 4. <a> 태그가 갖고있는 기본 기능을 끄기 위해서 preventDefault() 함수를 먼저 실행 시키고,
props.onChangeMode(event.target.id);
// 5. App()에서 props로 전달해준 onChangeMode를 추가하고, 매개변수에 고유 id값을 주입해야한다
// 5-1. 고유 id값을 주입하기 위해서 <a> 태그 내부에 id값을 부여한다.
// 5-2. t라는 변수에 App()에서 보낸 props의 요소가 담겨있고, App()으로 부터 오는 id 값도 t에 담겨있기 때문에 {t.id}를 <a> 태그에 심는다.
// 5-3. Nav() 함수 안에 있는 event를 일으키는 요소를 지정하기 위해 event.target을 설정하고, 그 target의 id를 가져오기 위해 매개변수는 결과적으로 event.target.id가 된다.
}}>{t.title}</a>
</li>)
}
return (
<nav>
<ol>
{lis}
</ol>
</nav>
}
function App() {
const topics = [
{id:1, title:'html', body:'html is ...'},
]
return (
<div>
<Header title="WEB" onChangeMode={()=>{
alert('Header');
}}>
</Header>
<Nav topics={topics} onChangeMode={(id)=>{
// 1. onChangeMode라는 prop을 만든다.
// 1-1. props를 통해서 전달하는 함수의 첫번째 매개변수로 id를 전달한다.
alert(id);
// 2. 고유 값을 이용해서 각 <li>별로 고유값이 적혀있는 경고창을 리턴한다.
}}>
</Nav>
</div>
)
}
출처: 생활코딩 React 2022년 개정판 1~6