리액트 할때 map 중요
컴포넌트를 재사용하기 위해서 map 사용
리액트에서는 컴포넌트의 복제품이 배열의 개수만큼 생긴다
const arr = [1,2,3,4,5]
arr.map((num) => {
return <Component />
});
// 결과는 컴포넌트 5개가 생긴다
<Component />
<Component />
<Component />
<Component />
<Component />
예를들어 props 를 사용하면
const arr = [1,2,3,4,5]
arr.map((num) => {
return <Component num={num}/>
});
// 결과는 컴포넌트 5개가 생긴다 이런식으로
<Component num={1}/>
<Component num={2}/>
<Component num={3}/>
<Component num={4}/>
<Component num={5}/>
컴포넌트 맵 돌릴때 key 있어야됨!!!!!
props 넘겨주는것처럼 넘겨야됨
key는 고유값
나중에 필요한 부분만 렌더할려고 누가누군지 알아야되기 때문에 고유한 키가 있어야 한다
값 수정 있을때 불필요한 렌더를 하지 않으려고
그래서 예를 들어 배열에 인적사항을 담은 여러 객체가 담겨있으면 서로 겹치지 않는 고유값을 키로하면 좋음
// 맵에서 두번째 인자는 인덱스
근데 원본데이터인 arr의 데이터가 삭제되면 인덱스도 바뀔수도 잇으므로 고유값을 하는 것을 추천
arr.map((num, index) => {
<Child key={index} num={num} />
})
http에서 post나 get이나 둘다 요청
겟은 나 이거 주세요
포스트는 나 이거 보낼테니까 이거에 대한 답 주세요
요청은 무조건 프론트에서
컴토넌트의 저장소는 state
state에다가 백엔드에서 요청해 받은 자료를 저장
호출을 어느 시점에 하느냐가 중요
호출은 첫번쨰 렌더가 끝난담에 호출
리액트 라이프 사이클
componentDidMount
컴포넌트가 마운트가 됐으니 이거 할거야
마운트는 이 컴포넌트가 화면에 보여진다는 뜻
가장 처음 렌더가 끝난뒤 componentDidMount
딱 한번만 돌음
그래서 데이터를 요청할때 많이 쓰임
왜냐하면 계속 돌면 요청을 계쏙해서데이터를 계속 갖고오니까
그래서 콘솔로 찍어보면 한번만 찍히는걸 알 수 있다
componentDidMount() {
console.log("CDM")
}
render() {
console.log("render");
return(
내가보여줄 JSX
)
}
하면 맨처음에 render , CDM 찍히고 State 가 없데이트 되어 다시 render 되어도 CDM은 찍히지 않는데
처음 렌더 뒤에 딱 한번만 실행되기 때문 (componentDidMount 는)
사실 constructor 도 한번만 실행
constructor에서도 api 호출해도 되나
호출 시기가 다르기 때문
constructor는 맨처음 불리고 그냥 하나의 약속이다
여기다가 데이터를 호출하면 어디다 쓸지 모르기때문
왜냐하면 처음 렌더된 뒤에 jsx의 뼈대가 구축되는데
구축된 다음에 데이터를 받아오면 이 데이터가 어디서 쓰일지 아는데
맨처음 호출할때 데이터도 같이 호출해버리면 어따쓸지 모르니까
html에서 자바스크립트 태그 바디태그 맨 밑에 놓는거랑 똑같
페치는 백엔드에 요청해서
그거에 대한 응답이 돌아온 다음에 덴 실행
함수안의 함수 는 콜백함수인데 어떤일이 일어나고 난후 실행하는 함수
btn.addEventListener('click', clickHandler());
저렇게 쓰면 안된다
왜냐하면 클릭하고 싶을때 이벤트가 실행되어야 하는데 그 안에 함수를 먼저 실행해버리면
크릭도 하기전에 이벤트가 실행되기 때문이다
componentDidMount() {
//호출
console.log("CDM") // 콘솔로 먼저 한번 찍어보기
fetch("API 주소")
.then(res => res.json()) // json -> js로 , 들어오는 대답에 .json() 을 붙임
.then((res.json() 에 대한 응답을 인자로) => {
// console.log(res) // 로 맞게 찍혔는지 확인
return this.setState({users: res})
}
}
그래서 빈배열 하나 선언하고 그 정보를 state에 빈배열에 넣어놓은 다음에
그 배열에서 정보 뽑아쓰기
그래서 데이터를 받아서 처리할줄 알아야함
엄청 복잡한 구조로 오니까
그래서 렌더 첫번째 줄에서 콘솔로 먼저 응답받을 데이터를 넣을 배열을 먼저 한번 찍어본다
그래서 맨처음 렌더돌떈 빈배열
그다음엔 응답받은 데이터가 들어옴
GET
내가 원하는 데이터를 달라고 요구
"http://10.58.1.33:8001/users/log-in" 여기서 end point(users/log-in) 내가 원하는 정보
디폴트값은 GET
end point 명은 프론트 리스트가 와야될 곳이니 명확하게 알 수 있는걸로
/products/10 (10은 프로턱트의 아이디(pid))
fetch ('api 주소') -> 써준 주소에다가 하나의 요청
인자 하나면 기본적으로 GET
요청에 대한 대답이 들어왔을때 .then() 함수가 들어옴
비동기 (하나의 요청이고 대답이 언제 돌아올지 모른다)
fetch ('api 주소')
.then()
console.log(~~~)
fetch에 요청한다음에 콘솔이 실행됨
요청에 대한 대답이 돌아오면 then이 실행된다
비동기 처리라
fetch("http://10.58.1.33:8001/users/log-in")
.then(res => res.json())
then에는 애로우 펑션을 쓰는데(콜백함수) fetch가 실행되어 대답이 들어왔을때 실행시킬라고
요청에 대한 대답이 들어오지않았는데 실행시키면 안되니까
리스폰스를 받아서 제이슨을 자바스크립트로 변환한것을 리턴한다
이것은 콜백함수 콜백은 어떤일이 일어났을때 실행 인자로 전달되는 함수
그래서 .then(res => res.json()) 이 정상적으로 끝났을때
또 then을 부른다
.then(res=> this.setState(userInfo: res.name))
위의 res랑 아래의 res는 다르다 아래의 res는 res.json() 에 대한 대답
POST
내가 가지고있는 데이터를 담아서 보낸다
포스트에서 "http://10.58.1.33:8001/users/log-in" 하면 이 db에 보내겠다 내가 가지고있는 정보를
추가 삭제할때 쓰임
products/10 에 price: 1300 보내면 프라이스 값을 업데이트 하겠다고
fetct함수의 첫번째 인자는 API주소고
fetct함수의 두번째 인자는 객체 형태인데 우리가 보내고싶은 정보를 넣어 api로 전달
백엔드가 딕셔너리 형태로 받아야되기때문 자스 객체 형태로 보낸다
fetch("http://10.58.1.33:8001/users/log-in", {
method: "POST", //메타 데이터, 백엔드에 무슨 요청을 하겠다고 알려줘야 하므로
headers: {
Authorization: localStorage.getItem("access_token")
},
body: JSON.stringify({ //우리도 바디로 담아서 보낼때 자스에서 JSON형태로 보낸다
username: this.state.userInputId, // 키이름은 백엔드에서 정한 이름
password: this.state.userInputPw // 값은 내가 보낼값 보통 스테이트값에 있음, 직접 하드코딩해도됨
})
})
JSON.stringify는 자스를 제이슨화 시키겠다
그 안에는 우리가 넘기고 싶은 자바스크립트의 정보를 넘기겠다
JSX안에서 자스 쓸라고 중괄호 쓰는거고 저 위에는 퓨어 자스 객체 형태니까 중괄호
리액트에서 리턴문안은 JSX 리턴문 위에는 퓨어자스
token
토큰은 내 꼬리표라고 생각하면 편함
로그인을 했어 백엔드에서 제대로된 유저인지 확인해야돼
데이터베이스에 저장되어있으면 토큰을 던져줘
토큰은 유저에 대한 정보
프론트(클라이언트) <-(포스트로 요청)-> 서버 <-> 백(디비)
맞으면 엑세스 토큰을 보낸다 모든 http 통신에 보내야한다 http는 stateless라
로그인되면
다음에 정보달라고 겟 요청 , 겟은 전에 로그인을 했는지 안했는지 알수없어서
그걸 알게해주는 방법이 토큰 (이사람은 로그인을 한 사람이다)
로그아웃 하는 순간 엑세스 토큰은 지워야함
엑세스토큰을 이용해 정보를 달라고하면 다시 로그인을해야함
fetch("http://10.58.1.33:8001/users/log-in", {
method: "POST",
//그다음 페치부터는 나는 인증된 유저입니다 라는 것을 알려주기위해
//headers는 솔직히말하면 거의 쓸일이 없는데 원래 추가 되는게있당 content-type: application
//메타데이터, 중요한 정보들 들어감
//민감한 정보니까 완전 중요한 객체 정보니까
//headers라는 키에 토큰을 가져와서 넣어줘야 된다
//객체 형태로 이건그냥 http에 보내기위한 룰
//{Authorization : ~ } 정해진거임
//기본적으로 프로덕트 리스트는 엑세스 토큰은 필요 없음
headers: {
Authorization: localStorage.getItem("access_token")
//일단은 로컬 스토리지 사용
},
body: JSON.stringify({
username: this.state.userInputId,
password: this.state.userInputPw
})
})
.then(res => res.json()) //JSON js 로 변환
.then(res=> localStorage.setItem("access_token", res.token))
//브라우저 스토리지에 저장, state에 저장하면 안됨, 토큰은 언제어디서나 접근해야됨
//최상위 저장소는 스토리지, 지금은 실습을 위해 로컬스토리지에 저장
//확인하려면 개발자 도구 어플리케이션 들어가서 확인