component 재사용, props 연습에 아주 좋은 것 같다
componentDidMount()
, fetch()
의 이해가 필요
index.js 에서
state = {
monsters: [],
userInput: ""
};
// 데이터 로딩
componentDidMount() {
fetch("https://jsonplaceholder.typicode.com/users")
.then(response => response.json())
//.then(response => console.log(response)) 데이터가 잘 들어왔는지 확인하기 위한
.then(response => this.setState({monsters: response}))
}
그래서 console로 먼저 출력해보면 데이터가 잘 받아진 것을 확인할 수 있다
mount는 요소를 DOM에 넣어, DOM이 생성되고 웹 브라우저 상에 나타나는 것을 말하며,
즉 render가 처음 돌고 나서 return이 끝났을때, JSX가 화면에 들어온 순간을 말한다
unmount는 component가 DOM에서 제거됐을때, render된 페이지가 사라졌을때를 말한다
component의 mount가 끝났다라는 의미로 component 출력물이 DOM에 렌더링 된 후에 실행된다
딱 한번만 실행되어 아래와 같은 일을 하기 좋다 (계속 render되면 데이터가 계속 업로드 되므로)
외부 라이브러리 연동
컴포넌트에 필요한 데이터 요청(fetch/axios/ajax/GraphQL)
DOM 관련 작업 : 스크롤 작업 / 크기 읽어오기 / 등등
- 참고 : MDN fetch
map 과제를 먼저 수행하기 위해서는 fetch()
함수를 알아야 한다
기본구조는
fetch('api 주소')
.then(res => res.json())
.then(res => {
// data를 응답 받은 후의 로직
});
하나 하나 풀어서 보면
1 =>
fetch("api 주소")
//백엔드에 API 주소를 보내 데이터를 요청// => JSON body 를 JS로 변환하는 요청
2 =>
.then(response => response.json())
// 인자로 내 요청에 대한 대답 (요청한 데이터에 대한 자료)를 가지고
// JSON body 에 있는 데이터를를 JS로 변환하는 요청
// JSON 파일은 JS에서 사용할 수 없으므로 변환 필요하다
3 =>
.then(res => {
// data를 응답 받은 후의 로직
});
// 먼저 console로 내가 원하는 데이터가 잘 들어왔는지 확인해보고
// response => console.log(response))
// data를 응답 받은 후 구현하고 싶은 로직을 적어준다
// setState로 API에서 받은 데이터 업데이트
index.js 에서 로직 자식 요소에 monsters 배열을 전달 (일단은 로직이 적용되기전 배열을 전달한다)
<CardList monsters={filterMonster} />
미리 되어있지만 Card 컴포넌트를 살펴보면
부모 요소에서 보낸 id, name, email를 토대로 리턴한다
코드
class Card extends Component {
render() {
return (
<div className="card-container">
<img
src={`https://robohash.org/${this.props.id}?set=set2&size=180x180`}
alt="몬스터 그림"
/>
<h2>{this.props.name}</h2>
<p>{this.props.email}</p>
</div>
);
}
}
export default Card;
여기서 2번, 부모 요소를 통해 전달받은 id, name, emeil을 가지고 crad component에 전달한다
import React, { Component } from "react";
import "./CardList.css";
import Card from "../Card/Card";
/***********************************************************
Card 컴포넌트를 import 한 뒤, props로 내려받은 데이터에
map 함수를 호출해 각각 다른 데이터를 가진 Card 컴포넌트들을 리턴해주세요!
Card 컴포넌트에서 필요로 하는 데이터는 id, name, email 입니다.
***********************************************************/
class CardList extends Component {
render() {
return (
<div className="card-list">
{this.props.monsters.map((monsters) => {
return (
<Card
key={monsters.id}
id={monsters.id}
name={monsters.name}
email={monsters.email}
/>
);
})}
</div>
);
}
}
export default CardList;
Key는 React가 어떤 항목을 변경, 추가 또는 삭제할지 식별하는 것을 돕는다
key는 요소에 고유한 특성을 부여하기 위해 배열 내부의 요소에 지정해야 한다
Key를 선택하는 가장 좋은 방법은 리스트의 다른 항목들 사이에서 해당 항목을 고유하게 식별할 수 있는 문자열을 사용하는 것이다
대부분의 경우 데이터의 ID를 key로 사용한다
항목의 순서가 바뀔 수 있는 경우 key에 인덱스를 사용하는 것은 권장하지 않는다
이로 인해 성능이 저하되거나 컴포넌트의 state와 관련된 문제가 발생할 수 있다
(미리 저장된 순서가 바뀌는 등)
참고자료 : React 공식문서 Map의 Key
입력된 input 값에 의해서 API에서 전달받은 monsters배열의 filter된 데이터를 가지고
CardList 컴포넌트에 전달하므로 index.js 에서
// SearchBox에 props로 넘겨줄 handleChange 메소드 정의
handleChange = (e) => {
this.setState({userInput: e.target.value});
}
input 태그에 입력된 값을 인자로 전달받아,
setState로 userInput 값을 업데이트 시킨다
메서드를 정의한 다음에 SerchBox 컴포넌트에 전달해야 한다
{/* <SearchBox handleChange=정의한메소드 /> */}
<SearchBox handleChange={this.handleChange} />
그러면 SearchBox 컴포넌트에서 부모요소로 부터 handleChange 메서드를 전달받아
onChange 이벤트를 발생시킨다
import React, { Component } from "react";
import "./SearchBox.css";
class SearchBox extends Component {
render() {
return (
<input
className="search"
type="search"
placeholder="Search..."
onChange={this.props.handleChange}
/>
);
}
}
export default SearchBox;
비교 대상은 monster 객체의 name 값,
소문자로 바꾼 monster.name 값과 userInput값을 비교,
filter 메소드가 반환하는 값을 변수에 저장 후 return 문 안에 CardList에 props로 전달
// 필터링 로직
const filterMonster = this.state.monsters.filter((monster) => {
return monster.name.toLowerCase().includes(this.state.userInput.toLowerCase())
})
데이터가 업데이트된 monsters객체에 filter 함수에
소문자로 바꾼 monster.name의 값이 사용자가 입력한 userInput 값을 포함하고 있는 것만
filterMonster에 반환해 화면에 출력시킨다
userInput도 소문자로 바꿔주면 좀 더 정확한 비교를 할 수 있다
기존
return monster.name.toLowerCase().includes(this.state.userInput)
사용자가 입력한 값이 소문자로 바꾼 monster.name 에 포함 되어있는 것만 반환
cd 작업 디렉토리
로 작업한 디렉토리 열기git status
로 현재 상태 확인git checkout 브랜치이름
작업한 브랜치로 이동git status
로 작업한 브랜치 현재 상태 확인git init
으로 현재 디렉토리를 git 저장소로 설정 (빈 저장소를 만들거나 초기화!)git add .
로 stage에 파일 추가git status
)git commit -m "커밋할 메시지"
메시지와 함께 바뀐 사항을 저장소에 기록git push origin 브랜치명
remote 저장소에 commit 내역 저장git status
로 상태 한번 더 확인 (브랜치 위치 잘 설정되어 있는지, 변경 사항 있는지)git add .
로 변경 내역 추가git status
로 맞게 추가 되었는지 확인git commit -m "커밋 메시지"
메시지와 함께 바뀐 사항 저장소에 또 기록git push origin "브랜치명"
다시 push 하기jin@jin-17Z990-R-AAC9U1:~/리액트 연습-6.16/react-exercises-2$ git status
현재 브랜치 jinsk
커밋하도록 정하지 않은 변경 사항:
(무엇을 커밋할지 바꾸려면 "git add <파일>..."을 사용하십시오)
(use "git restore <file>..." to discard changes in working directory)
수정함: src/2-monsters/index.js
커밋할 변경 사항을 추가하지 않았습니다 ("git add" 및/또는 "git commit -a"를
사용하십시오)
jin@jin-17Z990-R-AAC9U1:~/리액트 연습-6.16/react-exercises-2$ git add .
jin@jin-17Z990-R-AAC9U1:~/리액트 연습-6.16/react-exercises-2$ git status
현재 브랜치 jinsk
커밋할 변경 사항:
(use "git restore --staged <file>..." to unstage)
수정함: src/2-monsters/index.js
jin@jin-17Z990-R-AAC9U1:~/리액트 연습-6.16/react-exercises-2$ git commit -m "9기 진선경 monster 과제 index.js 수정본 입니다"
[jinsk 0084dd7] 9기 진선경 monster 과제 index.js 수정본 입니다
1 file changed, 1 insertion(+), 1 deletion(-)
jin@jin-17Z990-R-AAC9U1:~/리액트 연습-6.16/react-exercises-2$ git push origin jinsk
Username for 'https://github.com': jinsk9268
Password for 'https://jinsk9268@github.com':
오브젝트 나열하는 중: 9, 완료.
오브젝트 개수 세는 중: 100% (9/9), 완료.
Delta compression using up to 8 threads
오브젝트 압축하는 중: 100% (5/5), 완료.
오브젝트 쓰는 중: 100% (5/5), 488 bytes | 488.00 KiB/s, 완료.
Total 5 (delta 4), reused 0 (delta 0)
remote: Resolving deltas: 100% (4/4), completed with 4 local objects.
To https://github.com/wecode-bootcamp-korea/react-exercises.git
cb2f6f2..0084dd7 jinsk -> jinsk