1. Lifecycle과 useEffect
컴포넌트가 보이는 순간을 마운트(mount) 됐다고 볼 수 있다. 컴포넌트 안에서 state를 조작하면 업데이트(update)가 되기도 하고 필요없으면 제거되고 (unmount) 이런식으로 컴포넌트는 생명주기(Lifecycle)을 가진다. 중간중간 간섭이 가능하기 때문에 Lifecycle을 배운다.
이런식으로 갈고리를 달아서 이것을 제거되기 전에 실행할 코드를 실행하던가 업데이트될때 실행하던가 하는것 때문에 Lifecycle을 배우는 것이다.
컴포넌트에 갈고리 다는 법
이런식으로 작성할 수 있지만 요즘은 이런식으로 useEffect를 사용합니다.
이렇게 쓰게 된다면 mount, update 시 useEffect 안에 있는 코드가 실행됩니다. 실제로는 디버깅을 위해서 2번 실행되지만 발행하고 실제 사이트는 한번 작동합니다. 두번 작동하는게 싫으면 <React.StrictMode>를 없애면 됩니다.
useEffect는 mount,update시 동작하므로 count라는 버튼을 눌렀을때도 동작하게 됩니다.
하지만 console.log가 useEffect 밖에 존재해도 출력이 됩니다.
여기서 핵심인 것이 useEffect 안에 있는코드는 html 렌더링 후에 동작합니다. 하지만 이렇게 바깥쪽에서 실행 되는 것은 렌더링 되기 전에 실행이 먼저 되는것이므로 차이가 있습니다. 예를들어 for 반복문을 만들어 보겠습니다.
예를들어 이렇게 반복문을 만들어 놓으면 for 작업을 먼저 실행해놓고 그다음 html 문서가 나오므로 실행하는데 시간이 걸리지만 html 문서들을 렌더링 하고 나서 작업을 하면 조금 더 효율적으로 동작하게 됩니다.
*useEffect 안에 적는 코드들은 어려운 연산을 그래서 적어줍니다. 또한 서버에서 데이터를 가져오는 작업, 타이머 장착하는 것들은 다 useEffect 를 사용합니다.
*Side Effect : 함수의 핵심기능가 상관없는 부가기능을 말합니다.(부가기능) 그래서 useEffect 는 Side Effect 보관함 같다라고 말할 수 있습니다.
*setTimeout() 함수는 시간을 설정한 시간 후에 코드를 실행하겠다 라는 함수입니다. 이것을 사용해서 Detail 페이지 방문 후 2초지나면 <div> 2초 이내 구매시 할인 <div> 를 숨기게 만들어보겠습니다.
이런식으로 2초 뒤에 setAlert 가 false가 되어서 div 태그가 사라지는 걸 볼 수 있습니다. 하지만 여기서 궁금증이 있습니다.
마지막에 [ ] 이것은 무엇일까? 이 [ ] 안에 있는 값들이 변할때마다 실행된다는 말입니다. 그리고 컴포넌트가 mount 시, count라는 state가 변할 때 실행됩니다. 그래서 [ ] 이렇게 아무것도 넣지 않으면 mount 시(새로 페이지가 랜더링될때)에만 실행이 됩니다. 그래서 1회만 실행하고 싶으면 이렇게 [ ] 빈칸으로 적어주시면 되고 여러번 호출 하고 싶다. 예를들어 count 버튼을 누를때마다 실행하고 싶으면 이렇게 밑처럼(대충) 만들수 있습니다.
[ ] 이것을 적지않고
이런식으로 작성해 주신다면 mount 시 , update시 실행됩니다.
그리고 useEffect() 함수 안에 return문을 사용할 수 있는데 이것은 useEffect 동작 전에 실행되는 return() => {} 문이 발생하게 됩니다. 이것을 clean up function이라고 합니다.
이것은 언제 사용하느냐! 바로 타이머 같은 기능들이 있을때 기존 코드를 치우기 위해서 작성합니다.
이런식으로 작성해주면 페이지를 랜더링을 할때 조금 더 안전하게 코드 작성이 가능합니다. 그리고 useEffect 안에는 보통 서버로 요청을 하는 코드들이 작성이 되는데 2초정도 걸린다고 생각해봅시다. 그런데 2초 사이에 재렌더링이 되어버리면? 2초사이에 서버로 요청하는 코드가 발생하게 됩니다. 그렇게 된다면 이상하게 코드가 발생할 수 도 있습니다.
쉽게 말해서
이렇게 작성해준다면 return문 안에 console.log 1이먼저 동작하고 그 이후에 clearTime아웃이 실행되게 됩니다.
참고로 clean up function은 mount 시 실행이 안되고 unmount시 실행이 됩니다. 컴포넌트가 삭제될때 (다른페이지로 이동할 때)
최종 정리
즉 return 안에 작성하면 useEffect 실행 전에 한번 실행되고 unmount 됐을때 한번 더 실행이 된다 ( 비워주게 작성하는게 베스트)
2. 리액트에서 서버와 통신하려면 ajax 1
main 하단에 상품이 3개 나오는데 이 밑에 더보기 버튼을 만들어서 이 버튼을 누르면 상품 3개가 더 나오게 작성해보겠습니다.
이 ajax 통신은 우리가 서버에 데이터를 (Get,Post 등등) 요청해서 그것을 가져오거나 보내는 방식으로 사용합니다. 그래서 우리는 http://codingapple1.github.io/shop/data2.json 으로 요청을 보내면 상품 데이터를 줄 수있게 요청을 보내 봅시다. url로 요청을 보내면 새로고침이 됩니다. 하지만 ajax 사용하시면 새로고침 없이도 동작할 수 있습니다.
ajax 쓰려면 3개중 택 1 하시면 됩니다.
1. XMLHttpRequest
2. fetch()
3. axios 같은거
저는 axios를 사용해서 작업을 하겠습니다. 그러려면 axios 라이브러리를 설치해 줘야 합니다.
터미널에 npm install axios 설치하고 import 로 axios 사용하기
이렇게 get요청을 보내면 해당하는 주소로 요청을 보내고 요청 결과를 보여 주려면 . then () 을 사용하시면 됩니다.
이런식으로 버튼을 눌렀을때 데이터가 나오는 것을 볼 수 있습니다. 실제로 서버가 보낸 데이터를 보고싶다면 .data.data로 하시면 됩니다.
만약 ajax 요청이 실패할 경우 어떻게 되는지 보고싶으면 .catch 로 실행할 코드를 작성해주시면 됩니다.
그렇다면 여기에 더보기 버튼을 누르면 밑에 신발 3개가 추가적으로 나오게 해봅시다.!
이것을 하려면 shoes 에 데이터 몇개 추가해주세요 라고 데이터를 넣어주면 됩니다. 그럼 html도 알아서 나올것입니다.
그러면 이렇게 setShoes로 만들어주고 가져온 데이터를 shoes state에 추가해 주시면 됩니다.
이런식으로 작성하면 결국 더보기 버튼을 눌렀을때 상품이 잘 나오는것을 볼 수 있습니다.
2. 리액트에서 서버와 통신하려면 ajax 2 : post,fetch
그리고 이번에는 post 요청을 보내봅시다.
이런식으로 작성할 수 있지만 우리는 서버가 없기 때문에 이해만 하고 넘어가시면 될 것 같습니다.
그리고 동시에 ajax 요청을 여러개하려면
이런식으로 Promise.all 을 통해서 한번에 요청을 보낼 수 있습니다.
그리고 원래는 서버와 문자만 주고받을 수 있습니다. array나 object는 주고 받을 수 없습니다. 근데 위에서 어떻게 가능했냐 라면 array나 objct는
이런식으로 일명 JSON으로 문자 취급을 받을 수 있기 때문에 가능하게 됩니다. 결과.data는 실은 JSON으로 받아오고 이것을 axios가 array로 자동으로 바꿔줍니다.
그래서 만약 fetch를 사용하시게 될 경우
이런식으로 사용하셔야 합니다.
3. 리액트에서 탭 UI 만들기
1. html css로 미리 디자인
2. 탭 상태 저장해둘 state필요
3. state에 따라서 UI가 어떻게 보일지 작성
내가 버튼을 누르면 거기에 맞는 UI가 나오게 설정하면 됩니다.
이런식으로 boot strap 에서 nav를 찾아 만들어주고 import 를 해주시면 됩니다.
여기서 이 defaultActiveKey를 통해서 기본으로 눌려있을 버튼을 만들 수 있습니다.
그런 다음 2 번 탭 상태를 저장해둘 state 가 필요하기 때문에 만들어줍니다.
그리고 3번을 실행해봅시다.
state가 0 이면내용 0 이 보이게 1이면 1이 보이게 2면 2가 보이게 작성해봅시다.
이렇게 하고 버튼 1 누르면 내용 1 보이게 하고 싶다 까지 하려면 탭변경 스위치를 조작해주면 됩니다.
*Tip 1 . props. 어쩌구가 귀찮으면
이런식으로 작성할 수 있습니다. prop가 여러개면 탭 옆에 , props2 이렇게 작성하면 됩니다.
*Tip 2. 센스 좋으면 if 필요없을 수도 있습니다.
4. 멋있게 컴포넌트 전환 애니메이션 주는 법(transition)
전환 애니메이션은 부착하면 애니메이션 나오는 className 하나 만들고 원할 때 부착하면 됩니다.
1. 애니메이션 동작 전 className 만들기
2. 애니메이션 동작 후 className 만들기
3. className에 transition 속성 추가
4. 원할 때 2번 className 부착
먼저 첫번째 1,2을 실행해봅시다.
그리고 transition을 추가해줍니다.
이것은 opacity 가 변경될 때 0.5초에 걸쳐서 변경해주세요 라는 뜻입니다.
그렇다면 탭이라는 state 가 변할때마다 end를 부착하고 싶으니
또는
이런식으로 사용하실 수 있습니다.
최종본
왜 이렇게 작성해야 하냐면 리액트 18 버전 이상부터는 automatic batching 때문에 state를 변경하는 함수가 근처에 있으면 재렌더링을 시키지 x 한번만 재 렌더링을 합니다.
또한 css로 transform : scale(0); 이런거 쓰면 작아졌다 커졌다 하는 기능도 만들수 있습니다.
5. props 싫으면 Context API 써도 됩니다
Single Page Application 단점 : 컴포넌트 간 State 공유가 어렵습니다. 부모와 자식간은 props 전송은 가능합니다.
그리고 지금 까지의 컴포넌트 구조는 밑과 같고 shoes를 TabContent 까지 전송하려면 이런식으로 해야 합니다.
이렇게 된다면 컴포넌트가 10중첩이면 props를 계속 써줘야 합니다. 이런것들을 방지하고자
1. Context API(리액트 기본문법)
2. Redux 등 외부 라이브러리를 사용하시면 됩니다.
지금은 1번째 방법 Context API를 사용할 것이지만 성능이슈도 있고, 재활용이 힘들다는 단점 때문에 사용하지는 않지만 배워는 보겠습니다.
예시로 재고라는 새로운 state를 만들어 주겠습니다.
1번 상품의 재고가 10, 2번이 11, 3번이 12개라고 가정해봅시다. 당연히 props를 두번 쓰면 되겠지만 Context API를 활용하여 보겠습니다.
Context API
셋팅 1 . createContext()
context는 쉽게 말해 state 보관함 이라고 생각하시면 됩니다.
셋팅 2 . <Context> 로 원하는 컴포넌트 감싸기
셋팅 3 . 원하는 state를 보내주면 됩니다. value = { { state1, state 2...} }
이것을 Detail.js에서 사용하려면
1. Context를 import 해줍니다.
2. useContext 를 사용해줍니다.
useContext는 보관함 해체
이런식으로 state 에 있는 값들을 가져다 쓸 수 있습니다.
Detail컴포넌트 뿐만 아니라 그 자식들도 props 없이 사용이 가능합니다.
편한지 모르겠으면 사용 안하셔도 됩니다. 하지만 이걸 안쓰는 이유는
1. state 변경시 쓸데없는 것까지 재 렌더링이 됩니다. (비효율적 재렌더링)
2. 나중에 컴포넌트 재사용이 어려움
그래서 실제로는 Redux를 사용해서 많이 사용합니다.
'코딩애플 > React' 카테고리의 다른 글
[코딩애플] React 리액트 기초부터 쇼핑몰 프로젝트까지! (6/6) (0) | 2023.08.27 |
---|---|
[코딩애플] React 리액트 기초부터 쇼핑몰 프로젝트까지! (5/6) (0) | 2023.08.26 |
[코딩애플] React 리액트 기초부터 쇼핑몰 프로젝트까지! (3/6) (0) | 2023.08.23 |
[코딩애플] React 리액트 기초부터 쇼핑몰 프로젝트까지! (2/6) (0) | 2023.08.23 |
[코딩애플] React 리액트 기초부터 쇼핑몰 프로젝트까지! (1/6) (0) | 2023.08.21 |