[React] 서버로 부터 데이터 받기 -map()함수 (feat. 비동기함수와 Promise 타입)

Suji Kang·2023년 8월 30일
0

🐾 리액트에서 반복되는 컴포넌트 혹은 요소를 쉽게 그릴수있는 방법❓

map() 함수를 사용한다.
javascript 에 있는 배열안에 map 함수.
map 함수는 ❓ 기존에 있는 배열을 가지고 새로운 배열을 만들고 싶을떄 사용한다.

자 ❗️여기 map함수이다. 한번 봐보자❗️

let arr = [10,20,30];
let result = arr.map( (a, b, c) => { return 5; } );
console.log(result)
//결과값?  [5, 5, 5] 0:5 / 1:5 / 2:5

📌 map()함수 원리

arr.map( (a, b, c) => { return 새로만드는배열속요소 } );

  1. 인자: 로는 함수를 전달받는다.
    인자로 전달되는 함수 매개변수 3개를 설정할수있다.
    각각 요소, 인덱스번호, 원본배열이 매개변수에 대입된다.
  2. 동작 : 콜백함수를 기반으로 새로운 배열을 만들어준다.
  3. 결과 : 새롭게 만들어진 배열을 리턴한다.

계속해서 🔎 보면,

const MapPage = () => {
    let arr = [10, 20, 30];
    let res = arr.map(() => {
        return 5;
    });
    //callback 함수를보고 인식한다
    // 콜백함수는 배열의 갯수만큼 자동으로 반복하고 '5'는 요소가 된다
  //지금 있는 갯수는 몇개? 3개. 그래서 5를 return을 3번 해서!
    console.log(res);
    //결과값은?  [5, 5, 5] 0:5 / 1:5 / 2:5

📝 일반 javascript - div로 하나하나씩 다 만들어줬지? 🤨

import styled from "@emotion/styled";
    
const MapPage = () => {
    return (
        <>
        <h1>Map Page</h1>
        <div>제목입니다</div>
        <div>제목입니다</div>
        <div>제목입니다</div>
        <div>제목입니다</div>
        <div>제목입니다</div>
        <div>제목입니다</div>
        <div>제목입니다</div>
        <div>제목입니다</div>
        </>
    );
}

export default MapPage;

100개면 어쩔라고 ❓

먼저 다른 간단한 예시를 들어볼거야.

	let arr = [10, 20, 30];
    let res = arr.map((element, index, array) => {
        console.log(element, index, array);
        return element * 3;
    });
    console.log(res);
    //[30,60,90]

return (
        <>
            <h1>할일 목록입니다</h1>
            {res}
 			//여기에 res값을 보면 306090 으로 나온다. 리액트가 알아서 그려주기 떄문에
  			//여기서 하고싶은 말은 구지 여기서 밑에처럼 res0,1,2를 쓸필요가없다. 바로 다 그려주기때문에.
  			//res[0]
  			//res[1]
 			//res[2]
            <div>js 공부하기</div>
            <div>css 복습하기</div>
            <div>html 공부하기 </div>
            <div>team project 하기</div>
            <div>장보기</div>
            <div>청소하기</div>
            <div>잠자기</div>
            <div>밥먹기</div>
        </>
    );

그러면또 여기서 생각이 들지 요소로 jsx가 들어있다면 ❓

  let arr2 = [
        <h2>제목1</h2>,
        <h2>제목2</h2>,
        <p>안녕하세요</p>
    ];

return (
        <>
            <h1>할일 목록입니다</h1>
            {arr2}
			//<h2>제목1</h2>
        	//<h2>제목2</h2>
        	//<p>안녕하세요</p>
			//이렇게 출력이된다 바로 👍
            <div>js 공부하기</div>
            <div>css 복습하기</div>
            <div>html 공부하기 </div>
            <div>team project 하기</div>
            <div>장보기</div>
            <div>청소하기</div>
            <div>잠자기</div>
            <div>밥먹기</div>
        </>
    );

🐾 react에서 배열이 존재한다면, 배열을 그대로 jsx자리에 써도 해석하여 그려준다.

풀어보자!! 
arr = [10, 15, 20][5, 10, 15] 로 만들려면?
답은?👇
arr.map((element)=>{return element -5;});
//매개변수 element 받아서 return 값에 element 에서 -5를 해줘 

자, 이제 100개(7개지만)라고 가정하자 ! 요소를 만들어보자.
기존에 있는 배열기반으로 새로운 배열을 만들거야.

  let todoList = [
        'js 공부하기',
        'css 복습하기',
        'html 공부하기',
        'team project 하기',
        '장보기',
        '청소하기',
        '잠자기',
        '밥먹기'
    ];

 			<div>
                {todoList.map((todo) => (
                    <div>{todo}</div>
                ))}
            </div>

다됐는데..여기서 근데 이런 에러가 또 뜨지 😂❓

 Each child in a list should have a unique "key" prop.

반복을 통해서 그렸잖아 배열로, 그런데 컴퓨터 입장에서는 각각을 구분할수가 없기때문에,
만약에 7개중 한개가 삭제가되면 무엇이 삭제되었는지 알수가 없어, 그래서 각각을 구분하기 위해서 key값이 필요하다. 무슨값을 줘도 상관없음. 각각을 구분할수만 있으면. key={idx}

배열 속에 jsx들이 요소로 들어있고, 이를 그려줄때는 각각의 요소들을 구분할수 있도록
key라는 props(속성)을 추가해줘야한다.
key는 고유한 값을 가지고 있어야한다.

key={index} //index는 배열의 인덱스번호를 의미한다.     
key={element.id} //id는 고유한 값을 가지고 있어야한다.
<div>
     {todoList.map((todo, idx) => (
     <div key={idx}>{todo}</div>
  ))}
</div>

🐾 배열안에 객체

하나하나 또 언제 다 쓰고있을래 ❓

   return (
        <>
            <h1>글목록</h1>
            <WriteWrap>
                <WriteRow>
                    <p>1</p>
                    <p>글 제목입니다.</p>
                    <p>abc123@test.com</p>
                    <p>2021-09-01</p>
                    <p>2021-09-01</p>
                </WriteRow>
                <WriteRow>
                    <p>1</p>
                    <p>글 제목입니다.</p>
                    <p>abc123@test.com</p>
                    <p>2021-09-01</p>
                    <p>2021-09-01</p>
                </WriteRow>
                <WriteRow>
                    <p>1</p>
                    <p>글 제목입니다.</p>
                    <p>abc123@test.com</p>
                    <p>2021-09-01</p>
                    <p>2021-09-01</p>
                </WriteRow>
            </WriteWrap>
        </>
    );
};

export default MapPage;
        

📌 map() 함수로 바로 가즈아 🔎

import styled from "@emotion/styled";

const WriteWrap = styled.div`
    background-color: skyblue;
    border-radius: 20px;
    box-shadow: 3px 4px 12px rgba(0, 0, 0, 0.08);
    width: 80%;
    margin: 0 auto;
    padding: 10px 20px;
`;

const WriteRow = styled.div`
    display: flex;

    & p {
        text-align: center;
        flex-grow: 1;
    }

    & p:nth-child(1) {
        width: 10%;
    }
`;

 let postList = [
        {
            id: 5,
            title: '백과사전',
            writer: 'test@naver.com',
            createdAt: '2023-08-08',
            updatedAt: '2023-09-01'
        },
        {
            id: 78,
            title: '네이버란 무엇인가',
            writer: 'abc@naver.com',
            createdAt: '2023-08-08',
            updatedAt: '2023-09-01'
        },
        {
            id: 465,
            title: '카카오란 무엇인가',
            writer: 'kakao@naver.com',
            createdAt: '2023-08-08',
            updatedAt: '2023-09-01'
        }
    ]

return (
    <>
        <h1>글목록</h1>
        {postList.map((e, idx) => (
            <WriteRow key={e.id}>
  				//key값도 잊지말고!
                <p>{idx + 1}</p>
                <p>{e.title}</p>
                <p>{e.writer}</p>
                <p>{e.createdAt}</p>
                <p>{e.updatedAt}</p>
            </WriteRow>
        ))}
    </>
);
};

export default MapPage;

여기 잠깐 ❗️🔎 css & p:nth-child & p:nth-of-type 에 대해 알아보자고 🤨

<div>
    <p>1번</p>
    <p>2번</p>
    <a>3번</a>
    <h1>4번</h1>
    <p>5번</p>
    <h1>6번</h1>
    <h1>7번</h1>
</div>

👉 & p:nth-child(3)
 하면??? 정답은??? 
 없잖아 🤨 자식의 3번쨰 p tag 는 <a>3번<a/> 이잖아.
👉 & p:nth-of-type(3)
 하면??? 정답은??? 
 여러개의 태그 사이에서 3번째인 p tag인 <p>5번</p>

자 이제 실전이다 ❗️

🐾 서버로 부터 데이터 받아오기

📝 fetch(주소) 함수를 사용한다.

https://koreanjson.com/ - 가짜서버 연습용 에서 posts get요청을 해볼거야
결과로 배열을 달라고, 요청할거야


📌 비동기함수와 Promise 타입

fetch('koreanjson.com/posts')

  fetch('http://koreanjson.com/posts/')
        .then((response) => {
            console.log(response);
            return response.json()
        })

📍 1. 비동기함수이기 떄문에 결과가 나오지 않았음에도
일단 Promise 타입결과로 나온다.

Promise= {
    [status] : 'pending',
    [result] : 없다
}

아직 실질적 결과는 안나왔기에 result는 없고, status는 pending이다.

📍 2. 다른거 먼저 실행

📍 3. 데이터가져오기 완료(성공, 실패)

Promise= {
    [status] : 'fulfilled',
    [result] : {응답객체} // {title: '제목', content: '내용'}
}
Promise = {
    [status] : 'rejected',
    [result] : 에러 {응답객체} 
}

📌 then 안에있는 함수는 언제 실행될까?

fetch('koreanjson.com/posts')
	.then(함수)

promise 의 status가 pending에서 fulfilled바뀌면 실행되는 함수이면서 ,
해당 함수의 매개변수에는 promise result에 들어있던 값이 전달된다. (데이터 요청을 한후 .then 함수(result)실행을 한다.

이렇게 매체변수(Promise result가들어감) 에있는 response를 객체 를 받는다.

 fetch('http://koreanjson.com/posts/')
        .then((response) => {
            console.log(response);
            return response.json()
        })

객체안에 json 이 있다.

json 출력해보니, 안에는, 200칸짜리 배열이 있다.

 console.log(response.json());

 fetch('http://koreanjson.com/posts/')
        .then((response) => {
            console.log(response.json());
            return response.json()
        }).then((data) => {
            console.log(data);
        })

data 안에 배열이 있음.

이렇게 data를 가져올수있다.

📌 catch 안에있는 함수는 언제 실행될까?

Promise = {
    [status] : 'rejected',
    [result] : 에러 {응답객체} 
}
fetch('koreanjson.com/posts')
	.then(함수)
	.catch(함수)

catch안에 있는 함수중간에 오류가 발생하거나 rejected되었을떄 실행되는 함수이다.

오류가 났을떄,

 fetch('http://koreanjson.com/posts/')
        .then((response) => {
            console.log(response.json());
            return response.json()
        }).then((data) => {
            console.log(data);
        }).catch((err) => {
            //오류났을떄 실행 
            console.log(err);//오류객체
        })

📝 axios 사용법

https://axios-http.com/kr/docs/intro

npm install axios

설치후

import axios from "axios";

axios 라이브러리를 사용한다.(옛날에 fetch 없을떄 많이씀)

 axios.get('http://koreanjson.com/posts/')
        .then((res) => {
            console.log(res);
        })

axios에서는 .get함수 사용.
get요청후, res 매개변수 안에는 객체가 들어있다.

data라는 key값이 들어있고, res에서 data번째방데이터들이 있다.

axios.get('http://koreanjson.com/posts/')
       .then((res) => {
           console.log(res);
           console.log(res.data);
       }).catch((err) => {
           console.log(err);
       })

📌 이제 다 가지고온 data를 어떻게 사용할수있을까 ❓

re-rendering 될때마다 다시 실행되어야 하는 코드
최초로 렌더링 할때만 한번만 실행되어야 하는 코드
컴포넌트가 사라질떄 한번만 실행되어야 하는 코드

const MapPage = () => {
    let [axiosPostList, setAxiosPostList] = useState([]);
    let [fetchPostList, setFetchPostList] = useState([]);

    fetch('http://koreanjson.com/posts/')
        .then((response) => {
            console.log(response.json());
            return response.json()
        }).then((data) => {
            console.log(data);
            setFetchPostList(data);
        }).catch((err) => {
            //오류났을떄 실행 
            console.log(err);
        })

    axios.get('http://koreanjson.com/posts/')
        .then((res) => {
            console.log(res);
            console.log(res.data);
            setAxiosPostList(res.data);
        }).catch((err) => {
            console.log(err);
        })
}

이렇게하면 계속 무한반복 실행이 되어서 컴터 오류가 생기겠지? 🤨
그래서 여기서 useEffect()를 사용해야해 🔎

to be continued...🌟

profile
나를위한 노트필기 📒🔎📝

0개의 댓글