2020.코딩일지
[React-Effect Hook]useEffect() 본문
useEffect() 언제 실행되나?
컴포넌트 생성 후 처음 화면에 렌더링할 때,
컴포넌트에 새로운 props가 전달되며 렌더링될 때,
컴포넌트에 상태(state)가 바뀌며 렌더링 될 때,
--> 매 번 새롭게 컴포넌트가 렌더링 될 때! Effect Hook 실행된다.
**Hook사용시 주의점
최상위에서만 Hook호출하기.
React함수 내에서 Hook을 호출하기.
Effect Hook의 기본(예시)-명언제조
[명언제조]버튼을 클릭할때마다, 랜덤으로 명언이 나오며, 크롬의 타이틀 부분도 같이 변경된다.
import { useEffect, useState } from "react";
import "./styles.css";
export default function App() {
const proverbs = [
"좌절감으로 배움을 늦추지 마라",
"Stay hungry, Stay foolish",
"Memento Mori",
"Carpe diem",
"배움에는 끝이 없다"
];
const [idx, setIdx] = useState(0);
const handleClick = () => {
setIdx(idx === proverbs.length - 1 ? 0 : idx + 1);
};
return (
<div className="App">
<button onClick={handleClick}>명언 제조</button>
<Proverb saying={proverbs[idx]} />
</div>
);
}
//-----------------------------------
function Proverb({ saying }) {
useEffect(() => {
document.title = saying;
});
return (
<div>
<h3>오늘의 명언</h3>
<div>{saying}</div>
</div>
);
}
Effect Hook의 조건부실행
[]빈배열넣으면 컴포넌트 생성시 최초1회만작동 : 외부 API를 통해 리소스받아오고 더이상 API호출이 필요하지 않을때.
아무것도안넣으면 매번동작(컴포넌트 처음생성, props업데이트시, state업데이트시 마다마다)
(예시)-useEffect()는언제작동할까요?
import { useEffect, useState } from "react";
import "./styles.css";
import { getProverbs } from "./storageUtil";
export default function App() {
const [proverbs, setProverbs] = useState([]);
const [filter, setFilter] = useState("");
const [count, setCount] = useState(0);
useEffect(() => {
console.log("언제 effect 함수가 불릴까요?");
const result = getProverbs(filter);
setProverbs(result);
}, [filter]); //filter만 주시하고있다. 카운터를 눌러도 useEffect는 작동하지않는다.
const handleChange = (e) => {
setFilter(e.target.value);
};
const handleCounterClick = () => {
setCount(count + 1);
};
return (
<div className="App">
필터
<input type="text" value={filter} onChange={handleChange} />
<ul>
{proverbs.map((prvb, i) => (
<Proverb saying={prvb} key={i} />
))}
</ul>
<button onClick={handleCounterClick}>카운터 값: {count}</button>
</div>
);
}
//-----------------------------------
function Proverb({ saying }) {
return <li>{saying}</li>;
}
컴포넌트 내에서 AJAX요청
목록 내 필터링을 구현하기 위해서는 2가지 접근방법이 있다.
1. 컴포넌트 내에서 필터링 : 전체 목록 데이터를 불러오고, 목록을 검색어로 filter하는 방법
컴포넌트 내에서 필터링
import { useEffect, useState } from "react";
import "./styles.css";
import { getProverbs } from "./storageUtil";
export default function App() {
const [proverbs, setProverbs] = useState([]);
const [filter, setFilter] = useState("");
useEffect(() => {
console.log("언제 effect 함수가 불릴까요?");
const result = getProverbs();
setProverbs(result);
}, []); //최초1번만실행
const handleChange = (e) => {
setFilter(e.target.value);
};
return (
<div className="App">
필터
<input type="text" value={filter} onChange={handleChange} />
<ul>
{proverbs
.filter((prvb) => {
return prvb.toLowerCase().includes(filter.toLowerCase());
})
.map((prvb, i) => (
<Proverb saying={prvb} key={i} />
))}
</ul>
</div>
);
}
function Proverb({ saying }) {
return <li>{saying}</li>;
}
2. 컴포넌트 외부에서 필터링: 컴포넌트 외부로 API요청을 할 때, 필터링한 결과를 받아오는 방법
(보통, 서버에서 매번 검색어와 함께 요청하는 경우)
App.js
import { useEffect, useState } from "react";
import "./styles.css";
import { getProverbs } from "./storageUtil";
export default function App() {
const [proverbs, setProverbs] = useState([]);
const [filter, setFilter] = useState("");
const [count, setCount] = useState(0);
useEffect(() => {
console.log("언제 effect 함수가 불릴까요?");
const result = getProverbs(filter);
setProverbs(result);
}, [filter]); //필터칸에 검색어 입력할때만!
const handleChange = (e) => {
setFilter(e.target.value);
};
const handleCounterClick = () => {
setCount(count + 1);
};
return (
<div className="App">
필터
<input type="text" value={filter} onChange={handleChange} />
<ul>
{proverbs.map((prvb, i) => (
<Proverb saying={prvb} key={i} />
))}
</ul>
<button onClick={handleCounterClick}>카운터 값: {count}</button>
</div>
);
}
function Proverb({ saying }) {
return <li>{saying}</li>;
}
storageUtil.js
localStorage.setItem(
"proverbs",
JSON.stringify([
"좌절감으로 배움을 늦추지 마라",
"Stay hungry, Stay foolish",
"Memento Mori",
"Carpe diem",
"배움에는 끝이 없다"
])
);
export function getProverbs(filterBy = "") {
const json = localStorage.getItem("proverbs");
const proverbs = JSON.parse(json) || [];
return proverbs.filter((prvb) =>
prvb.toLowerCase().includes(filterBy.toLowerCase())
);
}
두 방식의 차이점 : 누가누가 부담스럽냐! 누가 더 부담스러운게 낫냐ㅋㅋㅋ
장점 | 단점 | |
컴포넌트 내부에서 처리 |
HTTP 요청의 빈도 감소 | 브라우저(클라이언트)의 메모리 상에 많은 데이터를 갖게 되므로, 클라이언트가 부담스럽.. |
컴포넌트 외부에서 처리 |
클라이언트가 필터링 구현을 생각하지 않아도 됨 |
빈번한 HTTP요청이 일어나며, 서버가 필터링을 처리하므로 서버가 부담스럽.. |
--->AJAX요청을 보내자!!
서버가 필터링하는 (storageUtil.js)대신, fetch API
* 외부API접속이 느릴경우도 있어서... 로딩화면 구현은 필수적이다! (loading indicator)
const [isLoading, setIsLoading] = useState(true);
//생략, LoadingIndicator컴포넌트 별도 구현했음을 가정
return {isLoading ? <LoadingIndicator /> : <div>로딩완료화면</div> }
useEffect(() => {
setIsLoading(true);
fetch(`http://서버주소/proverbs?q=${filter}`)
.then(resp => resp.json())
.then(result => {
setProverbs(result);
setIsLoading(false);
});
}, [filter]);
(미래의 나를위해ㅋ)
클라이언트가 서버에 요청을 덜 보내는 방법
Throttle a series of fetch requests in JavaScript
서버가 클라이언트에게 돌려줄 응답을 캐싱하는 방법
HTTP 및 서버 구현에 대한 이해가 필요합니다.
'JS & React' 카테고리의 다른 글
[React]개발상태관리 (0) | 2022.08.02 |
---|---|
React실습 - im-sprint-statesairline-client (0) | 2022.08.02 |
예시]state끌어올리기(Lifting State Up) 자식의 값을 부모에게 반영-보여줄게완전히달라진값 (0) | 2022.08.01 |
예시]state끌어올리기(Lifting State Up) 자식의 값을 부모에게 반영-Twittler React (0) | 2022.08.01 |
[React]코딩앙마-voca-(Create - POST) (0) | 2022.07.30 |