const element = <h1>Hello, world!</h1>;
이 문법은 문자열도 HTML도 아니다.
이 문법은 JSX
라고 부르며 자바스크립트의 문법 확장이다.(JavaScript + XML)
JSX
를 리액트와 함께 사용하여 UI가 실제로 어떻게 보일지 설명하는 것을 권장한다.
JSX 안에 자바스크립트 표현식을 중괄호 {}
로 묶어서 표현할 수 있다.
function formatName(user) {
return user.firstName + ' ' + user.lastName;
}
const user = {
firstName: 'Harper',
lastName: 'Perez'
};
const element = (
<h1>
Hello, {formatName(user)}! // 이렇게
</h1>
);
ReactDOM.render(
element,
document.getElementById('root')
);
속성에 따옴표를 이용해 문자열 리터럴을 정의할 수 있다.
const element = <div tabIndex="0"></div>;
속성에 중괄호를 이용해 자바스크립트 표현식을 포함시킬 수 있다.
const element = <img src={user.avatarUrl}></img>;
JSX
는HTML
보다는JavaScript
에 가깝기 때문에 ReactDOM은 HTML 속성 이름 대신 camelCase 속성 이름 컨벤션을 사용한다.
- ex) JSX에서
class
는className
이 되며,tabindex
는tabIndex
가 된다.
props
는 컴포넌트끼리의 정보 교환 방식!
부모 컴포넌트가 자식 컴포넌트에게 물려준 데이터이다.
- props는 반드시 위에서 아래 방향으로 흐른다. 즉 [부모] -> [자식] 방향으로만 흐른다.
- props는 반드시 읽기 전용으로 취급하며, 변경하지 않는다.
import React from "react";
function User(props) { // 자식 컴포넌트가 props 받음 (Object형태)
console.log(props); // 콘솔에 찍어보자
}
function App() {
const name = "hyewon";
const age = 18;
return (
<div>
<User name={name} age={age} /> // 부모 컴포넌트(App)가 자식 컴포넌트(User)에게 props 전달
</div>
);
}
export default App;
props는 object 형태이기 때문에 {props.name} 과 같은 방식으로 꺼내서 사용할 수 있다.
(그러나.. 아무도 그렇게 잘 안씀 😃 후술할 '구조분해할당' 방식을 사용하자.)
import React from "react";
function User(props) {
return <h1>{`제 이름은 ${props.name}이고 나이는 ${props.age}살입니다.😀`}</h1>;
}
function App() {
const name = "hyewon";
const age = 18;
return (
<div>
<User name={name} age={age} />
</div>
);
}
export default App;
props는 object 형태이다. 그래서 우리는 '구조분해할당'을 이용할 수 있다.
구조분해할당?
- 배열이나 객체의 속성을 해체하여 그 값을 개별 변수에 담을 수 있게 하는 JavaScript 표현식
const obj = { name: "hyewon" age: 18 }; const {name, age} = obj; console.log(name); // hyewon console.log(age); // 18
import React from "react";
function User({ name, age }) {
return <h1>{`제 이름은 ${name}이고 나이는 ${age}살입니다.😆`}</h1>;
}
function App() {
const name = "hyewon";
const age = 18;
return (
<div>
<User name={name} age={age} />
</div>
);
}
export default App;
여러개의 props를 받는다면 {}
안에 여러개의 props를 그대로 써주면 각각의 개별 변수에 값을 담을 수 있다. 어떤 props를 받는지 명시적으로 드러나기때문에 방법 2️⃣ 를 더 많이 사용한다.
❗️ [부모] -> [자식] 컴포넌트간 데이터 전달이 이루어지는 방법이 props 이다.
[부모]->[자식]->[자식의 자식]->[자식의 자식의 자식] 이 데이터를 받기 위해서는 무려 3번이나 데이터를 내려주어야 한다. 이걸 바로 prop drilling, props가 아래로 뚫고 내려간다 라고 한다.
-> 우리는 이와 같은 패턴을 피해야 하므로 나중에Redux
와 같은 데이터 상태관리 툴을 사용할 수 있다.😀
자식 컴포넌트로 정보를 전달하는 또 다른 방법이다.
import React from "react";
function User(props) {
console.log(props); // 콘솔에 찍어보자!
}
function App() {
return (
<div>
<User> 안녕하세요! </User>
</div>
);
}
export default App;
원래는 부모 컴포넌트에서 자식 컴포넌트로 props를 보낼 때 <User hello='안녕하세요' />
이런 식으로 보냈다.
그러나 <User>안녕하세요</User>
이렇게 쓰면 children 이라는 이름의 props를 보낼 수 있다.
(이름은 children으로 정해져있다.)
<User children="안녕하세요" />
이렇게 보내줘도 될 것 같지만..
children props는 주로 Layout 컴포넌트를 만들 때 사용된다.
Layout
컴포넌트 안에는 header
라는 컴포넌트가 있고, header
아래에 {props.children}
를 통해서 props를 받아 렌더링 하고 있다.
즉, Layout
컴포넌트가 쓰여지는 모든 곳에서 <Layout>…</Layout>
안에 있는 정보를 받아서 가져올 수 있는 것!
// Layout.js
import React from "react";
function Layout(props) {
return (
<>
<header style={{ border: "1px solid red", padding: "10px" }}>
<div>이건 모든 페이지에서 보이는 헤더입니다.</div>
</header>
{props.children}
</>
);
}
export default Layout;
// App.js
import React from "react";
import Layout from "Layout";
function App() {
return (
<Layout>
<div>여긴 App 컨텐츠가 들어갑니다</div> {/*children props*/}
</Layout>
);
}
export default App;
// index.js
import React from "react";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
이 코드를 통해, Layout
에 있는 header
가 보여지게 되고, “여긴 App의 컨텐츠가 들어갑니다.” 라는 문장이 Layout
의 props로 전달된다.
결과적으로 우리는 header
컴포넌트를 Layout
컴포넌트에서 한번만 작성하면 여러 페이지에서 모두 보여지게 할 수 있다.
// About.js
import React from "react";
import Layout from "Layout";
function About() {
return (
<Layout>
<div>여긴 About 컨텐츠가 들어갑니다</div> {/*children props*/}
</Layout>
);
}
export default About;
// index.js
import React from "react";
import About from "About";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<About />
</React.StrictMode>
);
💡 defaultProps란, 부모 컴포넌트에서 props를 보내주지 않아도 설정될 초기 값이다.
import React from "react";
function Child({ name, age }) {
return (
<div>
제 이름은 {name} 이고요 저는 {age} 살 입니다.
</div>
);
}
function App() {
return <Child />;
}
export default App;
Child 컴포넌트 입장에서는 부모 컴포넌트에서 name을 props 정보를 받기 전까지는 name 이 없다.
그래서 자식 컴포넌트 입장에서는 name이 무엇인지 알 수 없다.
결과적으로 자식컴포넌트는 화면에 아무것도 표시해주지 못하게 된다.
그래서 부모 컴포넌트에서 props를 받기 전까지 임시로 사용할 수 있는 props를 설정할 수 있다.
이후에 부모 컴포넌트에서 props를 받게 되면 설정된 defaultProps는 사라지고 받은 props로 바뀌게 된다.
import React from "react";
function Child({ name, age }) {
return (
<div>
제 이름은 {name} 이고요 저는 {age} 살 입니다.
</div>
);
}
// dafaultProps 설정
Child.defaultProps = {
name: "기본이름",
age: 0,
};
function App() {
return <Child />; // 부모 컴포넌트에서 아무런 props를 보내지 않음.
}
export default App;