[
[
{
"img" : "imgs/HeeYun/coffee.jpg",
"title" : "커피 1"
},
{
"img" : "imgs/HeeYun/coffee2.jpg",
"title" : "커피 2"
},
{
"img" : "imgs/HeeYun/coffee3.jpg",
"title" : "커피 3"
},
{
"img" : "imgs/HeeYun/coffee4.jpg",
"title" : "커피 4"
}
],
[
{
"img" : "imgs/HeeYun/blackCoffee.jpg",
"title" : "Black Coffee"
},
{
"img" : "imgs/HeeYun/coffee11.jpg",
"title" : "커피 11"
}
]
]
위의 코드는 이미지 사진들에 대한 mock data이다.
이 mock data는 전체 큰 배열과 내부에 두 개의 배열로 구성되어 있다.
{imgData[0].map((el)=>{
return ( < ImgList coffeeImg={el.img} coffeeName = {el.title}/> );
})}
const [imgData, setImgData] = useState([]);
useEffect(() => {
fetch('http://localhost:3000/data/imgData.json', {
method: 'GET'
})
.then(res => res.json())
.then(data => {
setImgData(data);
});
},[])
useState를 사용해서 mock data를 불러왔는데, 이 때 setter 함수를 사용했다.
setter 함수는 비동기적으로 작동해서 맨 처음 imgData의 초기 값인 빈 배열을 불러온다.
리액트에서는 렌더링이 화면에 커밋 된 후에야 모든 효과를 실행한다.
React는 return에서 map 함수를 반복실행할 때, 첫번째 시도에 데이터가 아직 안들어와도 렌더링이 실행된다.
{imgData.map((el)=>{
return ( < ImgList coffeeImg={el.img} coffeeName = {el.title}/> );
})}
바로 위의 코드는 내가 맨 처음 구현한 코드다. 이 때는 맨 위의 mock data처럼 두 개의 배열이 있는게 아니라 하나의 배열만 있었고, 그 때는 동작이 잘됐다.
imgData와 imgData[0]의 차이는 setter 함수가 비동기적으로 발생한다는 측면에서 달라지는 문제다.
imgData와 imgData[0]의 setter 함수가 공통적으로 맨 처음 가져오는 데이터는 useState안의 imgData state다.
imgData.map하면 처음부터 imgData 라는 이름의 mock data 전체를 불러들일 수 있다.
하지만 imgData[0].map 하면 처음 imgData mock data를 불러왔을 때는 두 개로 나눠진 배열들을 불러왔을 것 이다. 그래서 map함수는 어떤 걸 동작시킬지 인식을 하지 못해서 발생한 문제다.
만약 데이터가 아직 안들어오거나 즉시 처리할 수 없다면 && 방식을 사용한다.
형식은 { true && expression } 일 때는 항상 expression을 return하고,
{ false && expression } 일 때는 항상 false 값을 가져서 이 때는 무시하고 건너 뛴다.
imgData[0]&&imgData[0].map의 경우, 첫번째 시도에서는 imgData[0]이 undefined로 false 값을 가지기 때문에 리액트가 건너 뛰어버린다.
그 다음 두번째 시도에서는 이미 setter 함수가 imgData의 state를 업데이트 시켜서 imgData mock data가 두 개의 배열로 나눠진 상태임을 인지한 다음 동작해서 imgData[0]을 인식해서 true 값을 가진다. 이 때 expression이 동작된다.