import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
5. App.js 수정하기
import './App.css';
function App() {
return (
<div className="App"></div>
);
}
export default App;
6. npm run start 명령어 입력하여 리액트 앱 실행
const Viewer = () => {
return (
<div>
<div>현재 카운트: </div>
<h1>0</h1>
</div>
)
};
export default Viewer;
3. App.js 에 import 작성하기
import './App.css';
import Viewer from './component/Viewer'; //component 폴더의 Viewer 불러오기
function App() {
return (
<div className="App">
<h1>Simple Counter</h1> //제목 렌더링
<section>
<Viewer /> //Viewer 컴포넌트 렌더링
</section>
</div>
);
}
export default App;
const Controller = () => {
return (
<div>
<button>1</button>
<button>10</button>
<button>100</button>
<button>+100</button>
<button>+10</button>
<button>+1</button>
</div>
);
};
export default Controller;
3. App.js 수정하기
import './App.css';
import Viewer from './component/Viewer';
import Controller from './component/Controller'; //Controller 컴포넌트 불러오기
function App() {
return (
<div className="App">
<h1>Simple Counter</h1>
<section>
<Viewer />
</section>
<section>
Controller /> // Controller 컴포넌트 렌더링
</section>
</div>
);
}
export default App;
body{
padding: 20px;
}
.App{
margin: 0 auto;
width: 500px;
}
.App > section {
padding: 20px;
background-color: rgb(245, 245, 245);
border: 1px solid rgb(240, 240, 240);
border-radius: 5px;
margin-bottom: 10px;
}
[방식]
import './App.css';
import { useState } from "react";
import Viewer from './component/Viewer';
import Controller from './component/Controller';
function App() {
const[count, setCount] = useState(0);
const handleSetCount = (value) => {
setCount(count + value);
};
return (
<div className="App">
<h1>Simple Counter</h1>
<section>
<Viewer count = {count}/> //Viewer 컴포넌트에서 State변수 count의 값을 Props로 전달
</section>
<section>
<Controller handleSetCount={handleSetCount} /> // Controller 컴포넌트에 State값을 변경하는 함수 setCount 를 Props로 전달
</section>
</div>
);
}
export default App;
const Viewer = ({count}) => {
return (
<div>
<div>현재 카운트: </div>
<h1>{count}</h1>
</div>
)
};
export default Viewer;
⇒ 리액트에서는 부모가 리렌되거나 전달된 Props가 변경되면 자식 컴포넌트도 자동으로 리렌더 된다.
const Controller = ({handleSetCount}) => {
return (
<div>
<button onClick={() => handleSetCount(-1)}>-11</button>
<button onClick={() => handleSetCount(-10)}>-10</button>
<button onClick={() => handleSetCount(-100)}>-100</button>
<button onClick={() => handleSetCount(+100)}>+100</button>
<button onClick={() => handleSetCount(+10)}>+10</button>
<button onClick={() => handleSetCount(+1)}>+1</button>
</div>
);
};
export default Controller;
⇒ App 컴포넌트에서 이벤트 핸들러를 Props로 전달받아 count를 업데이트 시킨다.
import './App.css';
**import { useEffect, useState } from "react"; // useEffect 라이브러리 추가하기**
import Viewer from './component/Viewer';
import Controller from './component/Controller';
function App() {
const[count, setCount] = useState(0);
const handleSetCount = (value) => {
setCount(count + value);
};
useEffect(() => { // useEffect를 호출하고, (콜백함수, 배열)을 전달한다.
console.log("count 업데이트 : ", count);
}, [count]);
return (
<div className="App">
<h1>Simple Counter</h1>
<section>
<Viewer count = {count}/>
</section>
<section>
<Controller handleSetCount={handleSetCount} />
</section>
</div>
);
}
export default App;
[useEffect의 용법]
useEffect(callback, [deps])
import './App.css';
import { useEffect, useState } from "react";
import Viewer from './component/Viewer';
import Controller from './component/Controller';
function App() {
const[count, setCount] = useState(0);
const[text, setText] = useState(""); //State 변수 text 생성
const handleSetCount = (value) => {
setCount(count + value);
};
const handleChangeText = (e) => { //핸들러 함수 만들기
setText(e.target.value);
};
useEffect(() => {
console.log("count 업데이트 : ", count);
}, [count]);
return (
<div className="App">
<h1>Simple Counter</h1>
<section>
<input value={text} onChange={handleChangeText} /> //value 속성을 text에 전달하는 handleChangeText 함수 지정하기
</section>
<section>
<Viewer count = {count}/>
</section>
<section>
<Controller handleSetCount={handleSetCount} />
</section>
</div>
);
}
export default App;
2. text 값이 변경되었을 때도 useEffect의 콜백 함수를 호출하도록 하기
useEffect(() => {
console.log("count 업데이트 : ", text, count);
}, [count, text]); // text 변수 추가하기
useEffect(() => {
console.log("컴포넌트 업데이트");
});
⇒ 의존성 배열에 아무것도 전달되지 않았고, useEffect는 컴포넌트를 렌더링할 때마다 콜백 함수를 실행한다.
2. 의존성 배열에는 아무것도 전달하지 않지만, 콜백함수 실행시키기
import { useRef, useEffect, useState } from "react";
const didMountRef = useRef(false); //마운트 했는지 판단하는 변수(Ref 객체로 생성)
useEffect(() => { // 마운트 시점에 '컴포넌트 업데이트' 문자열 출력하지 않도록 하는 조건문
//의존성 배열이 없으므로 콜백함수는 마운트 시점에 실행되어야 함.
if(!didMountRef.current){ // 처음 마운트니?(!false = true : true니?)
didMountRef.current = true; //엉 마운트야(true로 바뀜)
return;
} else{// true니? (!true != true)
console.log("컴포넌트 업데이트"); //true니까 마운트 시점아니야 -> 리렌더구나
}
});
⇒마운트, 업데이트 시점 모두 콜백함수를 호출한다.
⇒ “컴포넌트의 마운트를 제어한다” 라고 표현한다.
useEffect(() => {
if(!didMountRef.current){
didMountRef.current = true;
return;
} else{
console.log("컴포넌트 업데이트");
}
});
**useEffect(() => { //빈 배열을 전달하면 컴포넌트의 마운트 시점에만 콜백함수를 실행시킨다.
console.log("컴포넌트 마운트");
}, []);**
⇒ App 컴포넌트는 처음에만 마운트하므로 “컴포넌트 마운트” 문자열은 한 번만 출력된다.
useEffect(() => {
setInterval(() => { //콜백함수는 다시 setInterval 함수를 호출
console.log("깜빡"); //밀리초 시간이 경과하면 첫번째 인수의 콜백함수를 실행한다.
}, 1000); //1초마다 문자열을 출력한다.
});
문제!!!!
⇒ setInterveral에서 인터벌을 생성한 다음에 이를 종료하지 않아서 발생!!!
⇒ 해결 : clearInterval 내장함수를 호출하여 종료해줘야 한다.
useEffect(() => {
const intervalID = setInterval(()=>{ //1. setInterval은 생성될 때 인터벌 식별자(id)를 반환한다.(**마운트 시점**에 실행)
// id가 intervalID에 저장됨.
console.log("깜빡");
}, 1000);
return () => { //2. useEffect에 인수로 전달된 콜백함수로 새 함수를 반환 (콜백 함수가 실행되기 전 이므로 **언마운트 시점에 실행**)
console.log("클린업");
clearInterval(intervalID); //3. 인수로 1에서 생성한 인터벌 식별자를 전달하여 앞서 생성된 인터벌을 삭제한다.
}
});
⇒ useEffect의 콜백함수가 반환하는 함수를 클린업 함수라고 한다.
컴포넌트를 리렌더링할 때마다 새 인터벌을 생성하고 기존 인터벌은 삭제한다.
⇒ useEffect의 콜백 함수가 또 다른 함수를 반환하는 클린업 기능을 이용하면 인터벌 같은 종료 후에도 남아있는 작업을 삭제할 수 있다.
function Even() {
return <div>현재 카운트는 짝수입니다</div>
}
export default Even;
**import Even from './component/Even'; //Even 컴포넌트 import**
<section>
<Viewer count = {count}/>
**{count % 2 === 0 && <Even />} // count가 짝수일 때(참일때), Even 컴포넌트를 렌더링해라**
</section>
2. Even 컴포넌트에서 useEffect를 사용기
import { useEffect } from "react";
function Even() {
**useEffect(() => { //의존성 배열로 빈 배열 전달, 콜백함수가 함수가 화살표 함수를 반환
//마운트 시점에서
return() => { // 언마운트 시점에서 호출
console.log("Even 컴포넌트 언마운트");
};
}, []);**
return <div>현재 카운트는 짝수입니다.</div>
}
export default Even;
⇒ 콜백함수가 함수를 반환하면 이 함수는 컴포넌트의 언마운트 시점에 실행된다."빈 의존성 배열로 인해 언마운트 시에만 클린업 함수가 호출되기 때문에 'Even 컴포넌트 언마운트'가 출력되지 않는다.”
1. Props의 전달방향은 (단방향 데이터 흐름)이고, State를 변경하는 이벤트는 (역방향)으로 전달된다.
2. 리액트 컴포넌트의 라이프 사이클 3가지는 (탄생(Mount)), (업데이트(update)), (죽음(unmount)) 이다.
3. useEffect에서 두번째 인수인 배열의 요소 값이 변경되면 (callback 함수)가 호출된다.
4. 의존성 배열에 아무것도 전달되지 않으면 (마운트 시점), (업데이트 시점)이 모두 실행된다.
5. 언마운트 시점에 미처 정리하지 못한 사항을 처리하는 일을 (클린업)이라고 한다.
6. (5번 정답)을 하기 위해서(clearInterval) 내장함수를 호출하여 종료해줘야 한다.
7. useEffect의 콜백함수가 화살표 함수를 반환하면 이 함수는 컴포넌트의 (언마운트 시점)에 실행된다.
1. useEffect()를 활용하여 마운팅 상태일때 "마운팅 상태입니다."를 콘솔창에 출력하고, 언마운팅 상태일때 "언마운팅 상태입니다." 라고 출력하는 함수를 작성하시오.
import React, { useEffect } from 'react';
function MyComponent() {
useEffect(() => {
//여기를 채우시오.
};
}, []);
2. 마운팅 상태일 때, 콘솔에 2초마다 "안녕"을 출력한다. clearInterval 내장함수를 이용하여 클린업 기능을 구현하여라.
import React, { useEffect } from 'react';
function MyComponent() {
useEffect(() => {
// 여기를 채우시오
}, []);
정답
1.
import React, { useEffect } from 'react';
function MyComponent() {
useEffect(() => {
// 컴포넌트가 마운트될 때 실행될 코드
console.log('마운트 상태입니다.');
// 언마운트될 때 실행될 코드
return () => {
console.log('언마운트 상태입니다.');
};
}, []);
2.
import React, { useEffect } from 'react';
function MyComponent() {
useEffect(() => {
const intervalId = setInterval(() => {
console.log('안녕');
}, 2000);
// 언마운트될 때 클린업 함수 실행
return () => {
clearInterval(intervalId);
console.log('클린업 함수: clearInterval 실행');
};
}, []);
출처 : 이정환, 『한 입 크기로 잘라먹는 리액트』, 프로그래밍인사이트(2023), p-.
Corner React.js 3
Editor: smurfs
[리액터 스타터3] project 2. [할 일 관리] 앱 만들기 1 (1) | 2023.12.01 |
---|---|
[리액트 스타터3] 8장. hooks (0) | 2023.11.24 |
[리액트 스타터3] 5장. 리액트의 기본 기능 다루기 2 (0) | 2023.11.10 |
[React.js 3] 5장. 리액트의 기본 기능 다루기 1 (1) | 2023.11.03 |
[React.js 3] 3장. Node.js - 4장. 리액트 시작하기 (0) | 2023.10.13 |