컴포넌트 애니메이션 주기 & 장바구니 페이지 만들기

무과장·2023년 7월 4일
1

react

목록 보기
25/30
  1. 애니메이션 동작 전 className 만들기
  2. 애니메이션 동작 후 className 만들기
  3. className에 transition 속성 추가
  4. 원할 때 2번 className 부착

위에 방법을 적용해보자

  1. 애니메이션 동작 전 className 만들기
//App.css
.start{
  opacity: 0;
}
  1. 애니메이션 동작 후 className 만들기
//App.css
.end{
  opacity: 1;
   transition: opacity 0.5s; /*opacity가 변경될 때 0.5초에 걸쳐서 변경해주세요 */
}
  1. className에 transition 속성 추가
//App.css
.end{
  opacity: 1;
   transition: opacity 0.5s; /*opacity가 변경될 때 0.5초에 걸쳐서 변경해주세요 */
}
  1. 원할 때 2번 className 부착
//detail.js
function TabContent({tab}){
  let [fade, setFade] = useState('');
   useEffect(()=>{
    setTimeout(()=>{ setFade('end')}, 100) //두 번째
    return ()=>{
      setFade('') // 첫 번째
    }
  },[tab])
  //clean up function 안에 fade라는 state를 공백으로 바꿔라.
  //clean up function이 뭐더라? useEffect 실행하기 전에 방 한 번 싹 치우고 실행될 수 있도록 하는거 
  return(
    <div className={`start ${fade}`}>  // 문자 중간에 변수 넣으려면 `문자${변수}문자`
      {[<div>내용0</div>, <div>내용1</div>, <div>내용2</div> ][tab]}
    </div>
  )
//start뒤에 end가 떨어지고 붙으면서 효과가 보이는데
// 저렇게 딱 붙어있으면 효과가 나오지 않는다.
// end라는 게 나중에 붙을 수 있도록 만들면 될 것 같은데...
//fade라는 변수를 만들어 그게 변하면 원할 때 값을 넣어주도록 했다. 
//위에 useEffect까지 써서 했는데 왜 안 되지?
//end라는 클래스명을 부착하는게 맞긴 한데 떼었다가 부착해야 에니메이션이 보임. 그래서 setTimeout 줌

완성 화면

근데 왜 setTimeout을 쓰지?

리엑트 18버전 이상부터는 automatic batch라는 기능이 생겼다.
state 변경함수들이 연달아서 여러개 처리되어야 한다면
state 변경함수를 다 처리하고 마지막에 한 번만 재렌더링된다.
그래서 'end'로 변경되는거랑 ''이걸로 변경하는거랑 약간의 시간차를 뒀다.


예를들어 state 변경한 함수들이 좀 근처에 있다 하면 이것들을 하나로 합쳐서 최종적으로 state변경을 한 번만 진행을 해준다.
state 변경함수를 쓸 때마다 재렌더링을 시켜주는 게 아니라 state변경이 다 되고 나서 마지막에 재렌더링을 딱 한 번 시켜준다.
어렵구먼...

오늘의 숙제 : Detail 컴포넌트 로드 시 투명도가 0에서 1로 서서히 증가하는 애니메이션을 줘보시오.

내가 한 숙제:

function Details(props) {
let [detailFade, setDetailFade] = useState(0);
  useEffect(()=>{
    setTimeout(()=>{setDetailFade('end')}, 100)
    return()=>{
      setDetailFade('')
    }
  },[])
  return (
    <div className={`container start ${detailFade}`}>
    </div>
}

css는 위와 똑같이 했다.
이걸 짜면서 해결됐던 궁금증!
하나의 div안에 className을 두 가지 정할 수 있을까?
큰 따옴표 안에 띄어쓰기만 해서 사용하면 된다고 한다.
우리의 코드로 예시를 보자면

 <div className={`container start ${detailFade}`}>

이건 className="container" 따로 className={start ${detailFade}} 따로인 셈이다. 사실 띄어쓰기로 구분하면 된다는 사실은 구글링을 통해 알아냈지만 {start ${detailFade}}이 두 가지를 어떻게 합쳐야할지 몰랐다. 저렇게 하면 되는구나!
오케이 해결!

자, 이제 장바구니를 만들어보자

//App.js
<Route path="/cart" element={ <Cart/> } /> 

cart.js파일 하나 pages에 만들고 부트 스트랩에서 Table 하나만 갖다 쓰자.
장바구니는 보면 대부분 테이블로 구성되어 있음.

import { Table } from "react-bootstrap"
function Cart(){
    return(
       <div>
         <Table> 
            <thead>
                <tr>
                <th>#</th>
                <th>상품명</th>
                <th>수량</th>
                <th>변경하기</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                <td>1</td>
                <td>안녕</td>
                <td>안녕</td>
                <td>안녕</td>
                </tr>
            </tbody>
        </Table> 
       </div> 
    )
}
export default Cart;

저장 후 App.js에 import하는 거 잊지 말고.
아! 그리고 절대 경로로 만드려고 jsconfig.json root에 파일 하나 만들어줬는데 안됐었잖아. 그거 vscode 껐다 키니까 되더라 ㅎ
위에 처럼 해서 /cart 들어가면

요로코롬 나옵니다.

근데!! 장바구니는 수시로 변해서 state를 만들어줘야 하는데 어느 파일에 만들어서 저장해줄거야?
물론 가장 상위 폴더인 App.js에 만들어주겠지!
부모껄 자식이 받아서 쓰는 건 되지만 부모가 자식껄 쓸 수는 없으니까.
그럼 계속 props로 받아쓸거야? 쓸 곳이 많은데 말이야.
그 때 쓸 수 있는게 context API나 redux다. 다음에 전자 배우고 그 다음에 후자 배울 거다잉.

profile
느리더라도 꾸준히 확실하게.

0개의 댓글