리액트에서 서버와 통신하기 위해선 ajax 방식을 사용하는데
우선 서버와, 요청방식에 대해 간략히 정리해보겠다
데이터를 요청하면 데이터를 전송해주는 간단한 프로그램
- 어떤 데이터인지 기재 -> URL로
- 어떤 방법으로 요청할지 기재 -> GET/POST
지금까지 get은 데이터 조회, post는 데이터 수정 이런식으로 암기하였지만 이제 서서히 이해가 가기 시작하였다
GET
- 말 그대로 데이터를 get 하는 것이다
- 당연히 수정, 업데이트는 불가하고 그냥 받기만 가능
- 요청방법 : url을 브라우저 주소창에 입력하기
POST
- 블로그를 포스팅하다의 그 post 이지 않을까?
- 무언가 변경사항을 post 할 때 post 방식을 쓰는 듯 하다
- 요청방법 :
<form action="요청할url" method="post">
하지만 GET/POST의 단점은 브라우저가 새로고침이 된다는 것이다
🚫 리액트는 브라우저 새로고침을 권장하지 않는다
📢 그래서 사용하는 것이 AJAX 이다
서버에 GET, POST 요청을 할 때 새로고침 없이 데이터를 주고받을 수 있게 도와주는 간단한 브라우저 기능
- XMLHttpRequest라는 옛날 문법 쓰기
- fetch() 라는 최신 문법 쓰기
- axios 같은 외부 라이브러리
우선 설치를 한다
npm install axios
버튼을 클릭하면 서버에 신발 데이터를 요청해서 받아오고 페이지에 띄워보겠다
URL : https://codingapple1.github.io/shop/data2.json
<button onClick={()=>{
axios.get('https://codingapple1.github.io/shop/data2.json')
.then((res)=>console.log(res.data))
.catch(()=> console.log('요청 실패'))
}
}}>다음</button>
- axios.get(url) 을 통해 해당 url로 get 요청을 할 수 있고
- 성공하면 .then의 파라미터를 통해 요청 결과를 받아온다 => res.data로 가져온 데이터만 확인 가능
- 실패하면 catch 문을 실행해준다
클릭한번 했을때 3개의 데이터 추가를 완료했었다
이번에는 한번 더 클릭했을 때 또 3개를 받아와서 추가해보겠다
URL : https://codingapple1.github.io/shop/data3.json
우선 클릭 횟수를 저장하는 state가 필요할 듯 하다
let [click,setClick]=useState(0);
return(
...
<button onClick={()=>{
setClick(click+1)
if(click==1){
axios.get('https://codingapple1.github.io/shop/data2.json')
.then((res)=>{
let newData=[...shoes,...res.data]
setShoes(newData)})
.catch(()=> console.log('요청 실패'))
} else if (click===2){
axios.get('https://codingapple1.github.io/shop/data3.json')
.then((res)=>{
let newData=[...shoes,...res.data]
setShoes(newData)})
.catch(()=> console.log('요청 실패'))
}
}}>다음</button>
click=1일때 로드하도록 조건문작성을 하였는데 클릭을 2번해야 데이터가 로드된다..?
click state 는 버튼 클릭하면 setter 함수를 통해 click+1로 변경되는데 이는 비동기적으로 작동한다
setClick 함수를 호출하고 나서, 해당 상태(click 상태)가 즉각적으로 업데이트 되지 않는다
대신에, 리액트는 상태 업데이트를 예약하고, 다음 렌더링이 일어날 때 새로운 상태 값을 사용하여 컴포넌트를 업데이트한다
예를들어
setClick(click + 1);
console.log(click);
윗줄은 click 상태를 현재 값에서 +1 증가시키도록 예약하지만(다시 렌더링할때 업데이트 됨)
밑줄은 아직 상태 업데이트가 되지 않았기 때문에 +1이 되지 않은 이전 상태의 click 값을 출력한다
click 상태 값이 바뀔 때마다 실행시키고 싶은 코드를 useEffect에 입력하고 dependency에 click 을 입력하면
click 이 바뀔때마다 console.log 출력해준다
useEffect(() => {
console.log(click);
}, [click]);
이제 출력되는 click의 값은 업데이트 된 click값이 된다!
function Main(){
let [shoes,setShoes]=useState(data);
let [click,setClick]=useState(0);
let [isLoading,setIsLoading]=useState(false)
useEffect(()=>{
if(click===1){
setIsLoading(true)
axios.get('https://codingapple1.github.io/shop/data2.json')
.then((res)=>{
setShoes((prev)=>[...prev,...res.data])
setIsLoading(false)})
.catch(()=> {
console.log('요청 실패')
setIsLoading(false)})
} else if (click===2){
axios.get('https://codingapple1.github.io/shop/data3.json')
.then((res)=>{
setShoes((prev)=>[...prev,...res.data])
setIsLoading(false)})
.catch(()=> {
console.log('요청 실패')
setIsLoading(false)})
}
},[click])
setter함수로 click 값이 변경할때마다 조건문으로 click 을 바로바로 검사해주기 때문에
1번 클릭 시 data2.json이
2번 클릭 시 data3.json이 잘 로드된다!
다시 말하지만 useEffect를 사용하지 않고 onClick안에서 setClick(click+1)바로 밑부터 코드를 작성한다면 변경된 click 값대로 조건문이 실행되지 않는다
& 연산자를 통해 조건을 만들어서 true 일때만 html을 보여주는 방식을 사용하였다
{click <2 && <button onClick={()=>{
setClick((prev)=>prev+1)
}}>다음</button>}
isLoading 이라는 state로 ajax 내에서 로딩관리를 하였다
let [isLoading,setIsLoading]=useState(false)
return(
...
{ isLoading && <p className="alert alert-danger"> 로딩중입니다</p>}
현재 리액트 부트스트랩의 그리드시스템을 사용하고 있는데
다음버튼을 클릭하여 상품이 추가되어 렌더링이 되면 한줄에 계속 추가되는 문제가 있었다
그래서 <Col>
태그의 속성을 추가였다
12를 기준으로 하여 계산하는 듯하다
xs={1}은 한줄에 12개
xs={2}은 한줄에 6개
xs={3}은 한줄에 4개 등등
function Card({data}){
return(
<>
{data.map((item,i)=>(
<Col key={i} xs={4}>
<Link to={`/detail/${i}`}>
<img src={`https://codingapple1.github.io/shop/shoes${i+1}.jpg`} alt="img" width="80%" />
<h4>{item.title}</h4>
<p>{item.price}원</p>
</Link>
</Col>
))}
</>
)
}
.then((res)=>{
let newData=[...shoes,...res.data]
setShoes(newData)})
이처럼 지금까지는 기존배열을 보존하기 위해 새로운 배열을 만들어서 setter 함수로 배열 값을 바꾸는 방식으로 진행하였다
하지만 setter 함수로 한번에 가능하다
setter 함수의 파라미터에는 그 전의 state 남아있다
즉 파라미터= shoes가 되는 것이다
그래서 바로 setter 함수에서 값 변경을 할 수 있는 것이다
.then((res)=>{
let newData=[...shoes,...res.data]
setShoes((prevShoes)=>[...prevShoes,...res.data]})
Main 컴포넌트에서 shoes state를 만들고 data를 이쪽에서 관리했기 때문!
state로 굳이 만든 이유는 state가 변경될 때마다 새로 렌더링해주는 리액트 특성을 이용하기 위함이었는데 이 shoes는 main컴포넌트에서만 사용되기 때문에 나는 data.json에 get 요청으로 받아온 데이터를 push 해주었다
if(click===1){
setIsLoading(true)
axios.get('https://codingapple1.github.io/shop/data2.json')
.then((res)=>{
data.push(...res.data)
setShoes((prev)=>[...prev,...res.data])
setIsLoading(false)})
.catch(()=> {
console.log('요청 실패')
setIsLoading(false)})
위의 코드처럼 setShoes 값이 변경되는 곳에서 data.json도 같이 변경시켜주면 된다