// App.jsx
function App() {
return (
<div className="App">
<Gallery />
</div>
);
}
export default App;
ReactJS
의 코드 구성은 다음과 같다. 리액트를 아예 모르는 상태에서 보면 App
이라는 함수가 HTML
을 반환하는 형식이다. 저렇게 구성된 App
은 기본적으로 생성된 index.js
파일에서 모듈 형태로 불러와지고, 다음과 같이 사용된다.
// index.js
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
create-react-app
을 통해 프로젝트를 실행하여 브라우저의 DOM
구성을 보면 항상 최상단 태그의 id
값이 root
인 것을 알 수 있다. 최상단 태그의 바로 밑에 <App />
을 붙이는 형태로 코드를 작성하면 App
에 있는 내용을 프로젝트에 붙일 수 있는 것이다. 어떻게 보면 당연한건데, 익숙하지 않은 부분이 있다. 바로 태그 이름이다, <Gallery />
와 같은 태그는 실제로 HTML
문법이 아닐텐데 어떻게 사용할 수 있는걸까?
이고잉 코치님의 수업 진행 방식 중 하나는 본인이 멘트 하나를 알려주면 수강생들에게 따라하라고 지시하는 형태이다. 실제로 저렇게 이야기를 하셨고, 수많은 수강생들이 위의 말을 열심히 따라서 외쳤다. 그래서 저게 무슨 말이냐면 그냥 소스코드로 설명하는 것이 편할 것 같다.
<div>
<h1>안녕하세요, 저는 디디입니다 !</h1>
<Profile /> // component 1
<PortFolio /> // component 2
</div>
실제로 존재하지 않는 Profile, PortFolio
태그는 내가 직접 만든 태그이다. 그러면 저 코드를 보고 이러한 의문이 들 것이다.
물론 태그에 대한 내용도 정의해야 하는데, 흔히 클래스형 컴포넌트와 함수형 컴포넌트가 존재한다. 요즘은 함수형 컴포넌트만 사용하는 경우가 많아 함수형으로만 설명을 진행하는데, 클래스 컴포넌트에 관해서 궁금하다면 이전에 리액트 찍먹할 때 정리해놨던 내 포스트를 참고하면 될 것 같다. 무튼 간에 함수형 컴포넌트를 만드는 과정은 다음과 같다.
// Profile.jsx
const Profile = (props) => {
return (
<>
<h2>{props.name}의 Skills</h1>
<ul>
<li>CSS</li>
<li>JavaScript</li>
<li>ReactJS</li>
</ul>
</>
);
};
export default Profile;
arrow function
을 굳이 사용하지 않아도 사용이 가능하긴 한데, 가독성을 위해서는 쓰는 것을 추천한다. 의미적으로 보면 Profile
이라는 함수를 만들고, 저러한 태그들을 반환하는 것이다. 그냥 저렇게 적어놓은 상태로 다른 곳에 import Profile from './Profile.jsx'
로 가져온다면 바로 <Profile />
와 같이 사용할 수 있다. 당연히 이러한 방식으로 컴포넌트들끼리의 합성도 가능하고, 분해해서 따로 파일을 관리하는 것도 가능하다. 나중에 상태 관리로 들어가면 알게 되겠지만, 불필요한 랜더링을 방지하기 위해 컴포넌트를 어느정도 세분화 하는것도 중요하다.
Profile
이 인자로 받는 props
는 또 뭐야?라는 의문을 제기할 정도라면 어느정도의 눈썰미가 있다는 것이다 ! 이전에 자바스크립트나 객체 지향 언어를 공부했다면 생성자를 통해 초기값이나 필요한 값 등을 할당했던 경험이 있었을 것이다. 비슷한 느낌으로 사용된다, 정말 간단한 예제 코드를 만들어봤다.
// Profile Component 사용 부분
<Profile name = '디디'>
// Profile Component 선언 부분
// 방법 1
const Profile = (props) => {
return (
<>
<h2>{props.name}의 Skills</h1> // 디디의 Skills
...
</>
);
};
//방법 2
const Profile = ({name}) => {
return (
<>
<h2>{name}의 Skills</h1> // 디디의 Skills
...
</>
);
};
props
를 활용하여 통째로 값들을 가져오고, props.name, props.age
처럼 내부 값들을 하나씩 빼서 쓰거나 ({name, age, ...})
와 같이 가져와서 곧바로(방법 2 참고) {name}
처럼 사용하는 방법도 있다. 취향 따라 알아서 작성하면 되겠지만, 개인적으로 방법 2와 같이 구조분해를 해서 사용하는 것이 가독성에서 우월하다는 느낌을 받는다.
그리고 변수, 함수 등을 tag
내에서 사용하는 경우 무조건 중괄호 { ... }
을 사용한다. 사실 이건 이벤트 쪽 내용을 작성하면서 추가적인 설명을 할 것 같은데 미리 알아두는 것이 좋을 것 같아 추가로 적어놓는다.
<></>
가 있는데, 저건 꼭 필요한거야?return (
<div></div>
<div></div>
) // Bad
return (
<>
<div></div>
<div></div>
<>
) // Good
리액트의 컴포넌트가 리턴하는 태그는 무조건 하나의 최상위 태그로만 구성되어야 한다. 트리로 치면 depth
같은 느낌인데, 같은 깊이의 최상단 태그들이 여럿 존재하게 된다면 에러가 뜨게 된다. 그래서 이러한 경우 그냥 아무 의미가 없는 <></>
를 상단, 하단에 붙여주면 되고, 그러고 싶지 않다면 전체 태그를 <div>
태그로 감싸주면 된다. 만약 최상위 태그가 하나만 존재한다면 굳이 수정하지 않고 그대로 진행하면 된다.