⚛️ React/문제풀기 (코딩애플: React)

React : 더보기 버튼을 누를 때마다 다른 get주소 데이터 불러오기 (+로딩중)

Zoeeey 2023. 6. 1. 11:51

조건

더보기 버튼을 1번과 2번 누를 때 각각 다른 get 주소 상품 데이터를 불러오고, 3번 누르면 더이상 상품이 없다고 표시한다.


풀이

  1. '3번 이상 더보기 버튼을 눌렀을 시 더이상 상품 없음 알림''더보기 버튼 클릭 횟수'state로 작성했다.
  2. 버튼 클릭 시 클릭 횟수를 1 증가시키는 콜백함수(handleClick)를 작성해 버튼 이벤트핸들러 안에 넣었다.
  3. 더보기 버튼 클릭 시 실행될 콜백함수(moreProduct)를 작성했다.
    - ajax로 상품데이터를 불러오기 전 loading을 실행시켰다. (setLoading(true);)
    - 클릭 횟수에 따른 url을 변수로 만든 후, if문으로 처리하였다. (3번 이상 클릭 시 '상품 없음 알림' true, '로딩' false, ajax 실행을 중단하기 위해 return)
    - get으로 url 변수를 불러오고, 가져온 데이터(response.data)newProduct에 저장하였다.
    - copy 변수를 만들어 기존 상품 목록(props.shoes)와 새로운 상품 목록(newProduct)를 합쳤다.
    - 합쳐진 상품목록props.setShoes로 shoes를 바꾸어주었다.
    - loading을 종료했다.
  4. useEffect 안에 버튼을 클릭할 때마다 (정확히는 click 상태 변수에 변화가 생길 때마다) click횟수가 0이 아닐 시 moreProduct를 실행하도록 사이트 이펙트를 넣었다.
function Main(props){
  let [loading, setLoading] = useState(false);  // 로딩 상태를 관리하는 상태 변수
  let [alertmore, setAlertmore] = useState(false);  // 추가 상품 없음 알림 상태를 관리하는 상태 변수
  let [click, setClick] = useState(0);  // 버튼 클릭 횟수를 관리하는 상태 변수

  let handleClick = function(){
    setClick(click + 1);  // 버튼 클릭 시 클릭 횟수를 1 증가시킴
  }

  let moreProduct = function() {
    setLoading(true);  // 로딩 상태를 true로 설정하여 로딩 중임을 표시

    let url;
    if (click === 1) {
      url = 'https://codingapple1.github.io/shop/data2.json';  // 첫 번째 클릭 시 데이터2.json을 가져옴
    } else if (click === 2) {
      url = 'https://codingapple1.github.io/shop/data3.json';  // 두 번째 클릭 시 데이터3.json을 가져옴
    } else if (click > 2) {
      setAlertmore(true);  // 세 번째 클릭 이상일 경우 추가 상품 없음 알림 상태를 true로 설정하여 알림을 표시
      setLoading(false);  // 로딩 상태를 false로 설정하여 로딩을 종료
      return;  // 중복 호출 방지를 위해 함수를 종료
    }

    axios.get(url)  // axios를 사용하여 URL에서 데이터를 가져옴
      .then((response) => {
        let newProduct = response.data;  // 가져온 데이터를 newProduct 변수에 저장
        let copyShoes = [...props.shoes, ...newProduct];  // 기존 상품 목록(props.shoes)과 새로운 상품(newProduct)을 합친 새로운 배열을 생성
        props.setShoes(copyShoes);  // 합쳐진 상품 목록을 설정
        setLoading(false);  // 로딩 상태를 false로 설정하여 로딩을 종료
      })
      .catch(() => {
        console.log(`실패자`);  // 요청 실패 시 에러 처리
      });
  }

  useEffect(() => {
    if (click !== 0) {
      moreProduct();  // 클릭 횟수가 0이 아니면 moreProduct 함수를 호출하여 추가 상품 가져오기
    }
  }, [click]);  // click 상태 변수가 변경될 때마다 useEffect가 실행되도록 설정

  return (
    <>
      <div className="main-bg" style={{backgroundImage : 'url('+ mainBg +')'}}></div>
      <div className="container">
        <div className="row">
          {loading && <Loading />}  // 로딩 중인 경우 Loading 컴포넌트를 렌더링
          {alertmore && <Alertmore />}  // 추가 상품 없음 알림이 있는 경우 Alertmore 컴포넌트를 렌더링
          {
            props.shoes.map((a, i) => (<Product shoes={props.shoes} i={i} key={i} />))  // 상품 목록(props.shoes)을 순회하며 Product 컴포넌트를 렌더링
          }
        </div>
      </div>
      <button className="" onClick={()=> { handleClick(); }}>더보기</button>  // "더보기" 버튼을 클릭하면 handleClick 함수가 실행되도록 설정
    </>
  )
}

function Loading(){
  return (
    <div className="alert alert-warning">
      상품 로딩중
    </div>
  )
}

function Alertmore(){
  return (
    <div className="alert alert-warning">
      상품이 더 없습니다.
    </div>
  )
}

알게 된 점

  • ajax를 get할 때 url을 변수 처리 할 수 있다.
  • 위 코드에서 useEffect로 moreProduct()함수를 실행처리하지 않고, 더보기 버튼 이벤트핸들러 안에 onClick={()=> {handleClick (); moreProduct(); }}를 넣으면 버튼을 한 번 눌렀을 시 로딩중 버튼만 나오고, 두 번 눌렀을 시 한 번 눌렀을 때 나와야 하는 상품데이터가 불러와지고, 세 번 눌렀을 시 두 번 눌렀을 때 나와야 하는 데이터가 불러와지는 오류가 있었다.
    - > 동기/비동기 관련 오류가 난다면 useEffect로 호출시기를 확실하게 주는 것이 좋을듯.. 왜인지 생각중

출처 : 코딩애플 https://codingapple.com/