01. 직접 짠 코드
📑 Header.jsx
const Header = () => {
return (
<div>
<h1>Simple Counter</h1>
</div>
);
};
export default Header;
📑 Viewer.jsx
import { useState } from "react";
const Viewer = () => {
const [count, setCount] = useState(0);
const countHandler = (e) => {
setCount(count + parseInt(e.target.innerText));
};
return (
<div>
<p>현재 카운트 :</p>
<h3>{count}</h3>
<div>
<button onClick={countHandler}>-1</button>
<button onClick={countHandler}>-10</button>
<button onClick={countHandler}>-100</button>
<button onClick={countHandler}>+100</button>
<button onClick={countHandler}>+10</button>
<button onClick={countHandler}>+1</button>
</div>
</div>
);
};
export default Viewer;
📑 App.jsx
import "./App.css";
import Header from "./components/Header";
import Viewer from "./components/Viewer";
import Controller from "./components/Controller";
function App() {
return (
<div className="app">
<Header />
<Viewer />
</div>
);
}
export default App;
02. 수정 코드
📑 App.jsx
import "./App.css";
import Viewer from "./components/Viewer";
import Controller from "./components/Controller";
import { useState } from "react";
function App() {
const [count, setCount] = useState(0);
const countHandler = (value) => {
setCount(count + value);
};
return (
<div className="app">
<h1>Simple Counter</h1>
<section>
<Viewer count={count} />
</section>
<section>
<Controller countHandler={countHandler} />
</section>
</div>
);
}
export default App;
- section 태그로 컴포넌트를 묶는 이유 : 컴포넌트들마다 동일한 스타일을 주기 위함
- App이 count 변수는 Viewr, setCount의 이벤트 핸들러는 Controller에게 전달
📑 App.css
body {
padding: 20px;
}
.app {
display: flex;
flex-direction: column;
gap: 10px;
width: 500px;
margin: 0 auto;
}
.app > section {
background-color: rgb(245, 245, 245);
border: 1px solid rgb(240, 240, 240);
border-radius: 5px;
padding: 20px;
margin-bottom: 10px;
}
📑 Viewer.jsx
const Viewer = ({ count }) => {
return (
<div>
<p>현재 카운트 :</p>
<h3>{count}</h3>
</div>
);
};
export default Viewer;
📑 Controller.jsx
const Controller = ({ countHandler }) => {
return (
<div>
<button
onClick={() => {
countHandler(-1);
}}
>
-1
</button>
<button
onClick={() => {
countHandler(-10);
}}
>
-10
</button>
<button
onClick={() => {
countHandler(-100);
}}
>
-100
</button>
<button
onClick={() => {
countHandler(100);
}}
>
+100
</button>
<button
onClick={() => {
countHandler(10);
}}
>
+10
</button>
<button
onClick={() => {
countHandler(1);
}}
>
+1
</button>
</div>
);
};
export default Controller;
POINT 1 ⭐
"데이터의 원천 state를 어떤 컴포넌트에 위치시킬지 생각하기"
특정값을 변경시켰을 때, 변경된 값을 컴포넌트가 화면에 바로 렌더링 하려면 state로 만들어야 하는데,
state는 컴포넌트 내부에서만 만들 수 있음
또한 props를 이용해서 값을 전달할 때는, 부모와 자식 관계에서만 가능하고,
형제 관계의 컴포넌트는 props를 이용해서 서로에게 값을 전달할 수 없음
그래서 하나의 state를 여러 컴포넌트에서 관리하게 될 경우, 반드시 이 컴포넌트들의 공통 부모가 되는 곳에서 state를 만들어야 함
리액트의 계층 구조
여러 개의 컴포넌트들이 서로 부모와 자식 관계를 이루며 계층 구조를 형성하는데,
특정 컴포넌트가 다른 컴포넌트에게 데이터를 전달할 때는 반드시
두 컴포넌트는 서로 부모 자식 관계를 가지고 있어야 함
props를 이용하여 데이터 전달은 부모에서 자식 방향으로만 가능
✅ state Lifting : 계층 구조상에서 위로 끌어올려 아래에 있는 컴포넌트들이 모두 공유할 수 있는 방법
✅ 단방향 데이터 흐름 : 데이터의 흐름이 위에서 아래의 방향으로 흐르기 때문에 직관적임
POINT 2 ⭐
"함수와 함께 인수를 전달한다면 콜백 함수로 전달하기"
부모가 자식에게 props로 함수를 전달할 때, 인수도 전달하고 싶다면
함수 즉시 호출인 onClick={countHandler} 나 onClick={countHandler(-10)} 대신
콜백 함수를 사용하여 onClick={()=>{countHandler(10}} 이렇게 전달해야 함
→ countHandler 함수를 이벤트 핸들러로 설정하고 해당 이벤트 헨들러에서 함수를 호출한 뒤 원하는 값의 인수를 넘겨야 함
참고자료
이정환 Winterlood, '한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지'
댓글