React JS
Monster 과제
useEffect() 훅을 사용하여 데이터 로드(fetch)하기
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/users", { method: "GET" })
.then((res) => res.json())
.then((result) => setMonsters(result));
}, []);
- useEffect( () => { 실행할 코드 }, [ 이 안의 state 중 뭔가가 변경되면 useEffect()가 실행됨 ] ) : 콜백함수와 state들을 요소로 갖는 배열을 인자로 갖는다. 두번째 인자인 배열을 비우면 페이지가 로드될 때 최초 1회만 실행된다.
- fetch( "API 주소", { method: "", 등 서버로 보낼 정보 } )
- .then( (앞에서 코드가 실행한 뒤 리턴한 값) => { 실행할 코드 & return } )
- json() : json 형식으로 바꿔주는 메서드.
- [주의사항] useEffect() 안에 fetch()도 쓰다보니 (), {} 등을 여닫는 게 헷갈린다. 어디서부터 어디까지가 인자고, 함수인지 잘 확인하기.
- [의문] console.log(monsters)를 useEffect 안 콜백함수에서 찍었더니 안나오고 useEffect 밖에서 찍으니까 안 나옴.
map() 메서드와 props를 사용하여 컴포넌트 재사용하기
return (
<div className="monsters">
<h1>컴포넌트 재사용 연습!</h1>
// CardList 컴포넌트로 monsters 스테이트 값을 props로 전달
<CardList monsters={monsters} />
</div>
);
---
function CardList({ monsters }) {
return (
<div className="cardList">
// 전달받은 monsters 배열에 map() 사용하여
// 각각의 monster 정보를 담은 객체를 props로 갖는 Card 컴포넌트 리스트 생성
{monsters.map((monster) => (
<Card key={monster.id} monster={monster} />
))}
</div>
);
}
---
function Card({ monster }) {
return (
<div className="cardContainer">
<img
alt="monster"
src={`https://robohash.org/${monster.id}?set=set2&size=180x180`}
/>
<h2>{monster.name}</h2>
<p>{monster.email}</p>
</div>
);
}
filter() 메서드를 사용하여 검색 기능 추가하기
function handleChange(event) {
setUserInput(event.target.value);
}
const filteredMonsters = monsters.filter((monster) => monster.name.toLowerCase().includes(userInput.toLowerCase()))
return (
<div className="monsters">
<h1>컴포넌트 재사용 연습!</h1>
<SearchBox handleChange={handleChange} />
<CardList monsters={userInput ? filteredMonsters : monsters} />
</div>
);
- filter() 메서드 : 콜백함수를 인자로 받음. 콜백함수는 filter 메서드가 실행된 배열의 각 요소를 인자로 받아 주어진 조건을 검사함. filter()는 배열의 각 요소에 대해 콜백함수를 실행하여 true를 반환하는 요소만 새로운 배열에 담아 반환함.
- 시행착오
- 문제 : 처음에 "monsters" state 값에서 filter를 써서 필터된 배열로 setMonsters 해주었는데, 그럼 "monsters" 배열의 요소(객체)가 사라져서 검색창의 input value를 지워도 원래의 "monsters" 정보를 되돌릴 수 없음.
심지어 왠지 모르게 input 값을 받는 게 한 박자 느려서 글자를 2자 이상 써야 작동하고, 한 글자 이전까지 받아들임. - 그래서 fetch 후 "monsters" 값을 받을 때, 최초의 "monsters" 값을 "initMonsters"라는 변수로 저장해두고 사용하고 싶었음.
- 하지만 useEffect()나 fetch() 후 then() 안에서는 변수를 선언해도 밖에서 쓸 수 없음. 함수 스코프를 갖는 let/const 변수가 해당 함수 안에서 갇히기 때문인 것 같음.
-
let initMonsters = []; useEffect(() => { fetch("https://jsonplaceholder.typicode.com/users", { method: "GET" }) .then((res) => res.json()) .then((result) => { initMonsters = result; // 여기서 혹은 setMonsters(result); }); initMonsters = monsters; // 여기서 할당 }, []); function handleChange(event) { setUserInput(event.target.value); setMonsters( initMonsters.filter((monster) => monster.name.toLowerCase().includes(userInput.toLowerCase()) ) ); } return ( <div className="monsters"> <h1>컴포넌트 재사용 연습!</h1> <SearchBox handleChange={handleChange} /> <CardList monsters={monsters} /> </div> );
- 그래서 Monster 컴포넌트 내 최상위 위치에서 "initMonsters" 변수를 let 키워드로 선언하고, useEffect() 안에서 데이터를 로드한 뒤 받아온 monsters 배열을 값으로 재할당해보았음. 하지만 다시 렌더링될 때 useEffect()를 거치지 않으면서 "initMonsters" 변수의 값이 다시 비게 됨.
- Assignments to the 'initMonsters' variable from inside React Hook useEffect will be lost after each render. To preserve the value over time, store it in a useRef Hook and keep the mutable value in the '.current' property. Otherwise, you can move this variable directly inside useEffect.
- 해결
- 가이드대로 "monsters" state는 그냥 두고, 새로운 변수 "filteredMonsters"에 filter되어 반환되는 값을 저장함.
- handleChange 함수에서는 input 값만 "userInput" state에 저장함.
- "userInput" 값이 있을 때(검색창에 뭔가 입력했을 때) "filteredMonsters"를, 그렇지 않을 때(검색하고 있지 않을 때) "monsters" state를 CardList 컴포넌트에 props로 넘겨줌.
- 문제 : 처음에 "monsters" state 값에서 filter를 써서 필터된 배열로 setMonsters 해주었는데, 그럼 "monsters" 배열의 요소(객체)가 사라져서 검색창의 input value를 지워도 원래의 "monsters" 정보를 되돌릴 수 없음.
참고) Javascript - Array filter 사용법 https://7942yongdae.tistory.com/49
공부할 것
React Hooks 이해하기 (1) https://velog.io/@gwak2837/React-Hooks%EC%9D%98-%EC%9D%B4%ED%95%B4
'TIL' 카테고리의 다른 글
[TIL-136] 위코드 37일차: Project1 - CSS / JS 코드카타 (0) | 2022.03.01 |
---|---|
[TIL-135] 위코드 36일차: JS 코드카타 (0) | 2022.02.28 |
[TIL-132] 위코드 33일차: JS 코드카타 (0) | 2022.02.25 |
[TIL-131] 위코드 32일차: React JS - 위스타그램 마무리 / JS 코드카타 (0) | 2022.02.25 |
[TIL-130] 위코드 31일차: React JS - 서버와 통신하기 / JS 코드카타 (0) | 2022.02.23 |