리액트를 알게된 지 2주, 좌충우돌 리액트 적응기 !
🎯 목표 : React 관련 주어진 키워드를 활용해 자료를 찾아보면서 적용하기
❗️ 코드 스포 주의 ❗️
componentDidMount()
메소드를 통해 라이프 사이클에 대한 이해를 높인다.fetch()
함수를 사용해 API 호출을 할 수 있다.Array.map()
함수를 통해 component를 재활용할 수 있다.props
를 사용해 단방향(부모 컴포넌트 -> 자식 컴포넌트)으로 데이터를 전달할 수 있다.Array.filter()
를 통한 검색기능을 구현할 수 있다.
- 아래 키워드들을 활용해 데이터 로딩을 처리해주세요!
componentDidMount()
fetch()
→ 호출할 API 주소 입력setState()
→ state 객체 내에monsters
라는 key 값에 저장
✏️ 키워드 이해하기
1. componentDidMount()
React 컴포넌트의 life cycle을 살펴보면, render 후 componentDidMount()
가 호출 된다. 따라서 화면에 가장 처음 그려져야하는 state 값들을 넣어주면 된다.
fetch()
함수를 통해 받아온 데이터를 받아 올 것이다. () 안에fetch할 데이터가 있는 API 주소를 불려오면 된다.setState()
는 state를 업데이트 하는 함수이다. 즉, monsters라는 key값의 state인 빈 배열[]
에 받아온 데이터를 저장해주면 된다.// Monsters.js
// 데이터 로딩
componentDidMount() { // task1 - mission1
fetch('API 주소') //task1 - mission2
.then(res => res.json())
.then(data => {
this.setState({ // task1 - mission3
monsters : data
})
})
- API 호출 후 저장한 배열을 자식 컴포넌트인
<CardList />
에 넘겨주세요. (props 활용)- 넘겨준 후
CardList.js
에서 props 를 콘솔에 찍어 확인해주세요.
setState()
로 업데이트 된 monsters의 state를 자식 컴포넌트인 <CardList />
에 넘겨준다.// Monsters.js
return (
<div className="Monsters">
<h1>컴포넌트 재사용 연습!</h1>
<SearchBox handleChange={this.handleChange}/>
<CardList monsters={this.state.monsters}/> // task2 - mission1
</div>
);
CardList.js
에서 처리할 수 있도록 props로 받아 온 값이 들어오는지 console을 통해서 확인한다.// CardList.js
class CardList extends Component {
render() {
console.log(this.props.monsters) // task2 - mission2
return <div className="card-list">
</div>;
}
}
export default CardList;
- 🚨
Array.map()
함수 사용법을 꼭 익히고 시작해주세요!- 넘겨받은 배열을 기준으로
Array.map()
함수를 활용하여<Card />
컴포넌트를 리턴해주세요.Card.js
에게 넘겨줘야하는 props 는 각 몬스터 객체의id
,name
,
Array.map()
map() 함수는 여전히 어렵지만...! 😇
this.props.monsters
로 전달된 배열 데이터안의 요소만큼 돌면서 내가 지정한 <Card />
라는 컴포넌트를 리턴하는 것이다.
Card.js
에게 넘겨줘야하는 props
map() 함수를 통해 전달된 데이터를 <Card />
라는 컴포넌트로 전달해주기 위해서는 해당 데이터의 key값을 <Card />
의 프로퍼티로 전달해주면 된다.
// CardList.js
class CardList extends Component {
render() {
return <div className="card-list">
{this.props.monsters.map((monsterList)=>{ // task3 - mission1
return(
<Card // task3 - mission2
key={monsterList.id}
id={monsterList.id}
name={monsterList.name}
email={monsterList.email}
/>
);
})}
</div>;
}
}
export default CardList;
- Card.js 컴포넌트 모양 및 구조
<div className="card-container"> <img src=이미지주소 alt="" /> <h2>Name</h2> <p>Email</p> </div>
- 이미지 주소 (
src
)
https://robohash.org/숫자?set=set2&size=180x180
카드마다 다른 이미지를 보여주기 위해 위 주소의숫자
부분을 props 로 내려받은id
로 대체해주세요.
CardList.js에서 전달한 데이터를 props로 Card.js로 받아오기
이미지, 이름, 이메일을 props로 받아와 주면 된다.
//Card.js
class Card extends Component {
render() {
return (
<div className="card-container">
<img src= {`https://robohash.org/${this.props.id}set=set2&size=180x180`} alt="monsterImage" /> // task4 - mission1 & 2
<h2>{this.props.name}</h2> // task4 - mission1
<p>{this.props.email}</p> // task4 - mission1
</div>
);
}
}
카드마다 다른 이미지를 보여주기 위해 위 주소의 숫자 부분을 props 로 내려받은 id 로 대체
😇 이 부분이 헷갈렸다...하하 백틱을 이용해서 사용하는게 참 쉬우면서도 어렵다. 결론은 src에도 props가 전달되어야하니까 {}
를 사용해서 jsx를 쓴다는 것을 명시해 주고, 그 안에 또 변화하는 props값을 전달해줘야하니까 ${}
를 사용해야한다. ${}
안에는 id 값을 넣어주면된다 !!!
이때, src는 하나의 문자열로 전달되어야하기 때문에 백틱으로 묶어주면 된다!!!
- SearchBox 컴포넌트에 정의한 handleChange 메소드를 넘겨준다.
- 호출 시 인자로 들어오는 이벤트객체(e)를 활용해 userInput 으로 setState.
- 여기서 비교 대상은 monster 객체의 name 값입니다.
- 소문자로 바꾼 monster.name 값과 userInput값을 비교.
- filter 메소드가 반환하는 값을 변수에 저장 후 return 문 안에 CardList에 props로 전달
필터 기능은 로직을 생각했지만 코드로 구현하기까지 힘들어서 구글링의 도움을 받았다.
✏️ 내가 생각한 로직
뭔가 실행되기까지 많이 허술한 로직...
🔑 구현 방법
handleChange
가 적혀있었다.React state를 업데이트하기 위해 모든 키 입력에서 handleChange가 동작하기 때문에 사용자가 입력할 때 보여지는 값이 업데이트
handleChange
를 통해 사용자가 입력할 때 보여지는 값이 업데이트되니까 이 값을 부모 컴포넌트에서 새로운 함수에 담아 자식 컴포넌트로 전달해주자.🔥 이 부분이 내가 생각할 수 없는 부분이었다. 자식 컴포넌트에서 변화한 값을 받아 부모에서 함수를 만들어서 실행하다니..! 이건 다른 기능들에도 많이 쓰일 것 같다는 예감 100...
handleSearchBox
: ''
이었던 userInput을 event.target.value로 입력된 값으로 바꿔주는 역할을 한다.//Monster.js
handleSearchBox = (event) => {
this.setState({
userInput: event.target.value
})
}
handleSearchBox
는 props를 통해 searchBox.js
로 전달된다.//Monster.js : props 전달을 위해 입력해주기 !
<SearchBox handleChange={this.handleSearchBox} />
//searchBox.js : props로 함수 받아오기
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값을 비교하여 필터조건을 걸어주면 된다..! 말만 쉽다..ㅎㅎ
🔑 먼저, 새롭게 배운 것이 있다. render() 함수 안에 변수를 정의 해줄 수 있다는 것이다.
🔑 그래서 나는 filter
함수를 InputFiltering라는 변수에 저장하여 비교하기로 했다.
const InputFiltering = this.state.monsters.filter((monsterName) => {
return();
})
이렇게 filter
함수를 정의해주고 내가 필터링해서 얻고싶은 값을 return()안에 넣어주면 된다. 내가 얻고 싶은 값은 1)소문자로 2)searchBox에 입력한 값이 3)포함된 4)몬스터의 이름이다.
//Monster.js
return(
monsterName.name.toLowerCase().includes(this.state.userInput)
);
즉, 소문자로 입력한 userInput에 실시간으로 입력되는 값들이 포함된 몬스터이름을 찾아서 보여줘! 라는 이야기다.
🔥하.. 자바스크립트 문법 더 공부해야겠다는 의지가 활활
//Monster.js
<CardList monsters={this.state.monsters} InputFiltering={InputFiltering}/>
처음엔 this.props.monster로 받아왔다면, 이젠 필터가 걸린 this.props.monster를 받아와야하기 때문에 이렇게 map() 함수를 돌리면 끝 !!!!
{this.props.InputFiltering.map((monsterList)=>{}
과제를 하기 전, 확실하게 props 개념에 대해서 알고 있는가에 대한 의문이 들었다. 기존에 작성한 html 코드를 react의 컴포넌트요소로, 또 여기에 state와 props를 적용하면서 나에게 새로 Input되어지는 지식들이 버겁고 정리가 안되있었다면, react 세션을 통해 배운 지식을 적용하고 내가 모르는 부분 ( map, filter 함수) 부분을 공부할 수 있었다.