반응형

이전에 팀프로젝트로 만든 파일을  로컬에서만 쓰다가 오늘 호스팅 하는 방법을 배워서

호스팅 하는 방법을 올려보려고 한다.

 

리액트파일과 서버파일이 있어서 두곳에 따로따로 호스팅 해줘야 한다. 

 

Node.js 서버 호스팅

HEROKU

https://dashboard.heroku.com/apps

 

Heroku

 

dashboard.heroku.com

위의 사이트에 들어가서 가입을 해줘야한다.

가입을 하면 로그인을 하고 create new app으로 들어가 준다

 

이제 여기서 이름을 설정해 주고 Create app을 누르면 깃허브리포지터리 같은 게 만들어진다.

 

만들고 나면 이런 창으로 이동하게 되는데 깃허브처럼 파일을 여기로 보내주면 된다

heroku로 push 하기 위해서는 heroku를 설치해줘야 한다. 

https://devcenter.heroku.com/articles/heroku-cli

 

The Heroku CLI | Heroku Dev Center

Last updated January 17, 2023 The Heroku Command Line Interface (CLI) lets you create and manage Heroku apps directly from the terminal. It’s an essential part of using Heroku. Install the Heroku CLI Pre-requisites The Heroku CLI requires Git, the popula

devcenter.heroku.com

링크로 들어가서 해당하는 운영체제와 옵션에 따라 설치해주면 된다.

 

설치하면 이제 호스팅 할준비가 끝났다 호스팅할 파일들도 준비를 좀 해줘 야한다

 

1. 호스팅 할 서버 파일이름을 index.js로 변경 

2. 호스팅 하는 파일의 port번호 변경

const port = process.env.PORT || 8080;
//지정해주는 포트번호가있다면 지정번호를사용하고 없다면 8080포트 사용

3.package.json 변경

 

 "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node index.js"
  },

 

이렇게 해준 뒤에 이제 깃허브에 push 하는 것과 똑같이 해주면 된다 

cmd 나 터미널을 이용해 주자

서버폴더위치에서 입력해줘야 한다.

 

주의사항*

서버를 깃허브에서 클론 해온 경우 node.module이 설치되어 있는지 확인 

없다면 npm install로 설치

 

. git 폴더를 지우고 처음부터 git init 하기 

 

업로드 전 서버를 실행시켜 보고 잘 실행되는지 확인!

 

json의 scripts.start 부분이 서버의 파일이름과 일치하는지 확인!!!

 

 

터미널에 입력

$ cd 프로젝트 위치
$ git init
$ git add .
$ git commit -m "heroku deploy" //커밋은 넣고싶은메모를 넣으면된다
$ heroku git:remote -a app name //이부분은 deploy에 쓰여있으니 복붙!
 --> 예시 $ heroku git:remote -a zzang9ha

$ git push heroku main //현재브랜치이름을 넣어주자 브랜치변경을 하지않았다면 master일수도 있다

 

push 까지 해 주고 오른쪽상단에 있는 open App을 눌러서 이런 창이 뜨면 성공이다 다른 에러창이 뜬다면 

json파일과 포트번호 그리고 모듈들이 잘 설치되어 있는지 다시 확인해 보고 리포지터리를 삭제한 다음 다시 만들어서 호스팅을 시도해야 한다..

 

서버의 데이터를 요청하는 주소로 이동하니 데이터를 잘 보내주는 걸 볼 수 있다! 이제 서버 끝 

 

 

React.js 호스팅

 

Vercel 가입하기

 

https://vercel.com/

 

Vercel: Develop. Preview. Ship. For the best frontend teams

Vercel is the platform for frontend developers, providing the speed and reliability innovators need to create at the moment of inspiration.

vercel.com

위 사이트를 통해서 github를 연결해서 바로 호스팅 할 수 있다.

깃허브로 회원가입이 가능하니 깃허브로 가입하고 빠르게 진행할 수 있다.

 

vercel에 리액트 파일을 호스팅 하기 전에 리액트 파일의 서버주소를

호스팅 된 노드서버주소로 변경해 준 다음 npm start로 실행해 보자.

리액트프로젝트의 서버주소 변경

나는 서버주소를 apiurl.js에서 변수로 선언해서 사용하고 있어서 여기 주소만 변경해 주겠다. 뒤에 / 가 필요하면 붙여주고 필요 없으면 때 주면 된다 서버에 요청을 어떻게 하는지 확인하자.

 

이제 다시 vecel로 돌아가서 

 

Add new에 project를 클릭하고 들어가서

깃허브를 연결해 주고 호스팅 하고 싶은 파일을 import 해주면 된다.

이제 이 화면에서 Deploy 해주고 기다리면 호스팅이 끝난다.

 

여기서는 수정할 부분이 있으면 로컬파일을 수정해서 다시 깃허브에 push 해주면

vercel에서 다시 호스팅 해준다.

 

https://team-project-thenadlee.vercel.app/

 

React App

 

team-project-thenadlee.vercel.app

호스팅 된 팀프로젝트.

반응형
반응형

타입스크립트 설치

타입스크립트를 설치하기 위해서는 Node.js를 설치해야한다.

https://nodejs.org/ko/

 

Node.js

Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.

nodejs.org

 

노드를 설치해주고

터미널을 실행시킨 다음 아래코드를 입력해주면 타입스크립트가 설치된다.

npm install -g typescript

 

타입스크립트를 설치하고나면 

이제 프로젝트를 만들 폴더에서 .ts 확장자로 파일을 만들어서 타입스크립트 코딩을 시작하면된다.

 

타입스크립트 컴파일설정

타입스크립트 프로젝트 폴더안에

tsconfig.json파일을만들어서 컴파일할때의 설정을 만들어줘야한다. 

 

 

Typescript 컴파일시 세부설정 (tsconfig.json) - 코딩애플 온라인 강좌

tsconfig 파일 생성하기 여러분 프로젝트 폴더에  tsconfig.json 이라는 파일을 하나 생성합시다. 여기엔 타입스크립트 ts 파일들을 .js 파일로 변환할 때 어떻게 변환할 것인지 세부설정이 가능합니다

codingapple.com

이렇게 json형식으로 옵션을 설정해주면된다.

 

타입스크립트로코드를 작성한후 터미널을켜서 tsc 를 입력하면 자바스크립트로 컴파일된다.

**혹시 powershell 에서  tsc사용이 안된다면 cmd로 바꿔서 실행하면 된다 powershell 에서는 정책문제때문에 tsc를 사용하지 못할수도있다.

 

이렇게 컴파일까지 할수있으면 타입스크립트를 사용할 준비는 끝이 났다

이제 타입스크립트를 사용하러 가보자. 

 

 

 

 

반응형
반응형

타입스크립트

 

http://www.typescriptlang.org

 

JavaScript With Syntax For Types.

TypeScript extends JavaScript by adding types to the language. TypeScript speeds up your development experience by catching errors and providing fixes before you even run your code.

www.typescriptlang.org

 

2012년에 발표됨 

대규모 javascript 애플리케이션 개발용도

마이크로소프트 개발, 오픈소스 프로그래밍 언어

자바스크립트의 상위집합이다 (자바스크립트의 모든기능을 포함하고 자바스크립트에 없는 기능도 가지고있음)

 

*자바스크립트와의 가장 큰 차이점!

자바스크립트는 동적인 언어이며 프로그램 구동중에 타입이 다이내믹하게 변경되지만

타입스크립트는 정적인 언어이며 프로그램을 작성할때. 타입을 정의해준다.

 

타입스크립트의 장점

1.버그를 줄이고 유지보수하기 쉽고 질좋은 코드 작성에 용이하다.

2.강력한 타입으로 대규모 개발에 용이하다.

3.자바스크립트 라이브러리와 편리한 사용

4.개발도구에서의 강력한지원.

 

ex) 자바스크립트를 실행하기전에는 알수없던 에러를 타입스크립트는 코딩하는과정중에 알수있게 도와준다.

 

프론트엔드 프레임워크와 타입스크립트

리액트(React)

         리액트와 타입스크립트의 호환성은 좋은편이다

         간단한 옵션을 추가하는것으로 타입스크립트를 사용할수있도록 지원한다.

뷰(vue)

         뷰 2.0부터 타입스크립트 사용가능

         뷰 3.0부터 타입스크립트 공식 지원

앵귤러(angular)

        버전 2부터 타입스크립트를 기반으로 만들어졌고 타입스크립트를 권장하고 있다.

 

 

타입스크립트를 사용할때에는 코드에디터로 비쥬얼스튜디오 사용을 권장하는데 비쥬얼스튜디오도 마이크로소프트에서 만들었고 타입스크립트도 마이크로소프트에서 만들어졌기때문에 자동완성이나 코드를 입력하는부분에서 더 부드럽게 작동한다고 한다.

 

반응형
반응형

마지막으로 글을쓴게 2월2일인데 마무리하고 정리하고 올리려니까 벌써 21일이 되버렸다.. 

원래는 중간중간 진행상황같은걸 정리해서 올려보고싶었는데 프로젝트를 진행하는데만 힘을너무쏟아서 블로그쪽은 생각도 안하고있었다.. 멀티가 이렇게나 안되다니.. 

프로젝트 끝난것도 저번주 월요일인데 프로젝트 끝나고 일요일에 정처기 필기시험이있어서 공부하느라 또 정리를 못하고 결국 22일이 되어버렸다.

 

그래도 어떤방법으로 만들었고 어떤걸 만들고싶었었는지 다시한번 정리해놔야 나중에 어떻게만들었는지

기억이 날것같아서 정리를 해볼려고한다.

 

 

프로젝트이름

The나들이

(떠나자 나들이 라는 의미로 만들었다)

 

기능

설정되있는 여행지 중에서 사용자가 선택하고 추천해주는 여행지중에서 여행 경로를 확인하고 관련한  정보를 얻을수있는 사이트

 

사용한라이브러리

@react-google-maps/api   구글지도기능을 이용하기위해 설치

redux-devtools/extension   redux상태를 파악할수있는 미들웨어 

html2/canvas                     화면을 캡쳐할수있게 해주는 라이브러리

antd                                    만들어진 스타일을 이용할수있는 라이브러리

node-sass                          scss를 이용해서 스타일을 적용하기위해 사용

axios                                   get,post요청을 하기위해서 사용.

react-cookie                        로그인 정보를 쿠키로 저장하기위해서 사용.

react-datepicker                  캘린더를 만들어주는 라이브러리

react-router-dom                라우터로 컴포넌트를 마운트시키는 라이브러리

react-redux                          리덕스로 상태값을 관리하는 라이브러리

react-icons                           아이콘을 만드는 라이브러리

styled-components             스타일이 적용된 컴포넌트를 만들어주는 라이브러리

 

필요할때마다 하나씩 설치를 하다보니 꽤 많은 라이브러리를 사용하게 됐다.. 점점 용량이 커지고 npm install 할때 걸리는 시간이 늘어나는게 이게 성능적으로 문제가 없나 싶었다.

꼭 필요한 라이브러리만 설치해서 사용하는게 좋은것같다.

(scss랑 styled-components 같이쓴건 좀 오바였지 싶다..)

 

데이터베이스

City 테이블 :각 나라별 위치좌표,이름,구글맵스에서 사용할 확대값 ,관련 블로그포스팅주소 , 월별 여행관련정보

SpotPlace 테이블: 나라의 추천관광지 이름,좌표,추천관광시간,이미지주소,추천경로순서

member 테이블: 회원가입관련자료: 유저코드,닉네임,비밀번호(암호화),이름,이메일

 

구현된 화면

팀원이 4명이고 다들 해외에서 살다오거나 연수경험이 있어서 각자 자기 지역을 담당해서

4개의 추천여행지를 만들었다

(캐나다,하얼빈,싱가포르:이건내가함!,제주도)

 

1200px 과 768px 에 반응형 디자인을 만들었다.

 

이제 실질적인 기능들이 모두 들어있는 일정만들기 페이지로 들어가보면.

기능이 좀 많은데 현재시간으로 제주도 날씨를 알려주고 (wheatherOnAPI를 이용했다)

달력으로 여행을할 기간을 찍으면 그 기간에 해당하는 여행팁을 알려준다.

오른쪽이 우리가 만들어놓은 추천 여행지인데 +를 눌러서 하나씩 일정을 추가시키면

오른쪽에서는 빠지고 왼쪽에 장소 추가되고 지도위에 마커가뜨고 마커들끼리 선으로 이어져서 동선을 쉽게 확인할수있다. (googlemapsAPI Marker , polyline 이용)

 

오른쪽 추천장소에 마우스를 올리면 해당장소로 지도의 포커스가 옮겨진다

(googlemaps 의 panTo기능을 이용)

아래 여행팁에 가려져있는 부분에 가고싶은 장소를 검색하면 해당장소로 포커스가 옮겨진다.

(구글지도의 자동완성기능사용 autocomplete)

 

지도위의 옵션버튼

 

여행기를 클릭하면 여행기블로그 포스팅이 연결된 팝업을 띄워준다.

<iframe> 태그를 이용해서 블로그 포스팅이있는 주소를 연결해서 보여줌

 

추천일정을 클릭하면 우리가 설정한 추천여행지와 추천코스 순서대로 보여준다

 

추천장소의 이미지가 슬라이더로 자동으로 넘어가고 아래 태그로 추천일정을 하나씩 선택하거나 모두선택버튼으로 모두선택할수있다. 선택하면 왼쪽에 장소가추가되고 지도에 마커와 경로가 그려진다.

장소들의 순서는 가장 좋다고생각하는 동선으로 순서를 정해서 하루정도에 돌아볼수있는 코스로 짜봤다.

 

 이제 일정을 모두 정하고 나면 일정생성버튼을 클릭하면 만든 경로의 이미지를 캡쳐해서 저장해준다.

 

기능들을 만들면서 좀 힘들었던 점이 많았는데 구글맵스 API가 자바스크립트로 사용하는 예시들은 인터넷에 많이 있는데 리액트라이브러리로 만드는 방법들은 예시가 많이 없어서 공식문서를 보고 여러가지 방법을 시도해서 만들었다. 사용된 예시가 많이 없어서 참고할만한게 별로없어서 힘들었다.

 

그리고 이미지를 주소에서 받아오다보니 이미지를 제대로 못받아와서 엑스박스가 뜨는경우가 있었다. 이런 문제를 처음봐서 당황했는데 이미지 태그에 옵션을 추가해주는걸로 해결할수있었다.

<img src={img} referrerpolicy="no-referrer" />

 

 

이미지를 캡쳐하는 라이브러리인  html2canvas도 처음사용해보는거라 어려웠는데 구글mapsAPI를 사용하니까  계속  CORS에러가 나서 이것도 열심히 구글링해서 구문한줄 추가해주니까 해결되었다.

html2canvas(document.getElementsByClassName('App')[0],{ useCORS: true }).then(canvas=>{
           onSaveAs(canvas.toDataURL('image/png'),'image-download.png')
})

 

 

 

페이지가많거나 내용이 많은 페이지는 아니었지만 기능적으로 새로운 api를 사용해보고 새로운걸 알아가면서 해야해서 시간이 좀 많이 걸렸던것같다.

API 관련한 부분은 선생님께 물어볼수도없어서 팀원들끼리 정말 열심히 찾아가면서 했던것같다. redux도 처음에 만들었던 reducer에서  2번정도는 구조를 바꾼것같다.

만들다보니 계속 막히는 부분이 생겨서 처음부터 제대로 다 구상을 해놓고 시작하면 이렇게 안해도될텐데 라는 생각을 계속했던것같다.. 사실 다 구상해놓고 만들수도 없지만..ㅠ 

 

4명이서 만들다보니 깃허브로 처음협업을해봤는데 종종 충돌이 생기고 머지가 안되는 상황이 종종 있었는데. 

이것도 찾아보면서 해결하다보니 확실히 팀으로 해보길 잘했다는 생각이 들었고 깃허브가 진짜 협업에 좋고 정신에 조금 해롭다는 걸 배웠다..

 

이제 개인프로젝트를 해야되는데 이번경험으로 리액트로 프로젝트만드는법에 조금 익숙해진것같아서 개인프로젝트는 조금 더 쉽게 할수있을것같은 생각이든다.

반응형
반응형

이제 3월 23일 수료가 2달 앞으로 다가오면서 슬슬 포트폴리오 압박이 들어오기 시작했다.. 

무조건 리액트로 만들어야하는데 아직 리액트로 엉성한 사이트도 제대로 만들어보지 못해서 걱정이 크다..

검색하다 보면 어떻게든 또 만들겠지 라는 생각으로 일단 함께할 팀원을 모아서 총 4명이서 여행코스를 만들어주는 사이트를 만들기로 했다. 각자 해외에 살다 온 경험이 있는 분들이라서 각 지역별로 추천관광지를 리스트업 하고 사용자가 추천관광지를 클릭하면 지도에 마크가 찍히고 서로 선으로 이어져서 여행동선을 한눈에 보기 편하게 만들어주는 사이트이다.

 

이걸 위해서 지도이미지와 마크 그리고 경로를 그려주는 기능이 필요했는데 마침 구글 maps API에서 모든 기능을 다 지원한다고 해서 일단 구글맵스를 공부하면서 어떻게 적용할지 고민하고 있다. 

 

리액트로 처음 페이지를만들면서 가장 고민되는 점은 어떤 변수들을 상태로 관리해야 하는지이다. 아직 해결은 못했지만 돌아가는 구성을 하나씩 맞춰보면서 사용자와 상호작용하면서 계속해서 변경되는 값들을 상태값으로 관리하려고 생각 중이다.

 

1. 메인페이지

1) 여행선택
2) 사이트소개
3) 이용방법

 

2. 로그인 페이지

 

3. 일정 만들기 페이지

1) 달력, 선택목록 컴포넌트
2) 멀티버튼 (지도 div위에 떠있게)
-- 이용방법, 여행기(블로그포스팅), 추천일정, 일정생성
3) 지도(googlemaps api)
3) 추천 여행지.

 

4. 일정생성 후 뜨는 페이지

일정저장, 이메일전송, 엑셀표출력


이렇게 어떤 페이지를 만들어야 하고 어떤 요소들이 들어가는지 미리 정리해두었고

 

각페이지 구조

각 페이지별로 배치를 어떻게 할지도 작성했다.

 

또 이번에는 제대로 협업을 해보기 위해서 github를 이용해서 collaborate에서

서로 코드리뷰를 하면서 코드를 계속 합쳐가면서 작업해보려고 한다.

(저번에는 그냥 구글드라이브에 각자 올려서 정리했더니 코드 합치는데만 반만년걸렸다..)

 

모든 게다 처음이지만 나중을 위해서 좋은 경험이 될 거라고 생각한다. 기능에 조금 욕심을 내고 싶지만

우선은 핵심기능부터 만들어보고 일정 안에 끝낼 수 있다면 다른 기능도 추가해서 넣어보려고 한다. 

요즘 chatGPT도 유행이던데 여행코스를 AI가 짜서 넣어준다던가.. 아니면 날씨를 API로 받아와서 일정별로 날씨를 알려준다던가 하는 추가적인 기능도 일단은 고려 중이다. 다 할 수 있으면 좋겠다..ㅎ

반응형
반응형

Redux-middleware

리덕스를 사용하는 이유 중에 하나는 미들웨어이다.

리덕스 미들웨어를 사용하면 액션을 디스패치하고 그 액션이 리듀서에 가기 전에 추가적인 작업을 더 해줄 수 있다. 

middleware의 실행위치

그래서 보통 비동기 방식으로 사용할 때 미들웨어를 많이 사용한다고 한다.

(서버에서 액션을 받아오면 리듀서에 가기 전에 비동기로 데이터를 받아서 보내줘야 하기 때문). 

 

리덕스 미들웨어는 개인이 필요한 용도로 만들어서 쓸 수도 있지만

보통은 만들어진 미들웨어를 받아와서 사용한다.

redux-thunk

redux-saga

redux-observable

redux-promise-middleware 등이 있다.

 

이번 포스팅에서는 리덕스 미들웨어가 어떤 건지 파악만 하기 때문에

직접 미들웨어를 만들어보고 대강의 구조를 파악해 보겠다.

 

1. 리듀서에 가기 전 추가적인작업

dispatch({ type:"add_todo" })


리덕스 미들웨어를 사용하면 액션이 디스패치된 다음,
리듀서에서 해당 액션을 받아서 업데이트하기 전에 
추가적인 작업을 할 수 있음. 

서버에 있는 값을 받아서 업데이트해 줄 때 주로 사용.(비동기)

 

간단한 리덕스 모듈을 만들고 미들웨어를 만들어서 적용해 보겠다.

 

1. 리덕스 모듈 만들기

액션타입, 액션생성함수 리듀서

modules/counter.js

//액션타입
const INCREASE = 'counter/INCREASE';
const DECREASE = 'counter/DECREASE';

//액션생성함수 --> 액션을 리턴
export const increase = ()=>({type:INCREASE})
export const decrease = ()=>({type:DECREASE}) 


//초기값
const initialState = 0

//리듀서
export default function counter(state=initialState,action){
    switch(action.type){
        case INCREASE:
            return state+1;
        case DECREASE:
            return state-1;
        default:
            return state;
    }
}

 

2. 루트 리듀서 만들기

모듈이 여러 개일 때는 리듀서가 여러 개이기 때문에 리듀서들을 하나로 합쳐서 store를 만들 때 사용한다.

modules/index.js

import { combineReducers } from "redux";
import counter from "./counter";

const rootReducer = combineReducers({ counter })

export default rootReducer

 

3. 스토어 만들기 , 전역에 스토어 사용하기

만들어진 rootreducer를 이용해서 스토어를 만들고 스토어를 사용할 수 있게 하위컴포넌트들을 묶어준다.

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { legacy_createStore as createStore } from 'redux';
import rootReducer from './modules';
import { Provider } from 'react-redux';

//스토어 만들기.
const store = createStore(rootReducer)
console.log(store.getState()) //상태값 조회
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

스토어를 만들었으니 상태를 관리할 준비는 다 끝났고 이제

counter의 상태를 이용해서 간단한 화면을 구현해 보자

 

화면적으로 보이는 프레젠테이셔널컴포넌트를 먼저 만들고

값을 전달해 줄 컨테이너컴포넌트를 만들어주겠다.

 

component/Counter.js

import React from 'react';

const Counter = ({number,onIncrease,onDecrease}) => {
    return (
        <div>
            <h2>{number}</h2>
            <button onClick={onIncrease}>+</button>
            <button onClick={onDecrease}>-</button>
        </div>
    );
};

export default Counter;

화면에 보여줄 현재 숫자를 number로 받아오고 버튼을 클릭했을 때

상태값을 + , - 해줄 함수로 onIncreaseonDecrease를 받아왔다.

 

이제 이 값들을 보내줄 컨테이너 컴포넌트를 보자.

containers/CounterContainer.js

import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import Counter from '../components/Counter';
import { decrease, increase } from '../modules/counter';


const CounterContainer = () => {
    const number = useSelector(state=>state.counter)
    const dispatch = useDispatch()
    const onIncrease=()=>{
        dispatch(increase()) //export const increase = ()=>({type:INCREASE})
    }
    const onDecrease=()=>{
        dispatch(decrease()) //export const decrease = ()=>({type:DECREASE}) 
    }
    return (
        <div>
            <Counter number={number} onIncrease={onIncrease} onDecrease={onDecrease}/>
        </div>
    );
};

export default CounterContainer;

useSelector counter의 상태값을 number로 받아서 Counter컴포넌트props로 보내준다.

useDispatchdispatch함수를 받아와서 디스패치를 실행하는 함수를 만들었다 onIncrease ,onDecrease 

dispatch에 액션객체로는 액션생성 함수를 넣어줬다.

이렇게 만들어준 함수를 Counter컴포넌트props로 넘겨준다.

 

이제 이 컨테이너 컴포넌트를 app.js에 넣어서 렌더링만 해주면 된다.

 

 

이제 여기에 미들웨어를 하나 만들어서 값이 리듀서로 가기 전에 작업을 할 수 있게 해 주겠다.

 

 

*리덕스 미들웨어 
미들웨어는 함수를 연달아서 두 번 리턴하는 함수.

const middleware = store => next => action =>{
	//하고싶은작업..
}

function middleware(store){
	return function(next){
		return function(action){
			//하고싶은작업..
		}
	}
}

위와 같은 구조가 미들웨어의 구조이다 store는 파라미터로 들어가고 함수를 두번 리턴해준다.

 

각 함수에서 받아오는 파라미터
-store 리덕스 스토어 store dispatch( ) / getState( ) / subscribe( ) 내장함수 들어있음
-next 액션을 다음 미들웨어에 전달하는 함수
ex) next(action)
-action 은 현재 처리하고 있는 액션객체

-next(action)을 해주지 않으면 action이 reducer나 다음 미들웨어로 넘어가지 않아서 에러가 생긴다.

 

middlewares/myLogger.js

const myLogger = store => next =>action=>{
    //액션 출력하기
    console.log(action)
    //next는 다음미들웨어 또는 리듀서 에게 액션을 전달.
    const result = next(action); //다음 미들웨어가 없어서 리듀서가호출되고 상태값이 변함
    // 업데이트 이후의 상태를 출력
    console.log(store.getState());
    //여기에서 반환하는 result값은 dispatch(action)의 결과물.
    return result
}

export default myLogger;

지금 보내주는 액션을 콘솔에 출력해 주고 action을 다음미들웨어로 넘겨준다.

미들웨어로 action이 넘어간 다음 바뀐 상태값을 출력해 준다.

 

이제 만들어진 이 미들웨어를 사용해 보자

store를 만들 때 미들웨어를 같이 넣어주면 된다.

import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { applyMiddleware , legacy_createStore as createStore } from "redux";
import { Provider } from "react-redux";
import App from "./App";
import rootReducer from "./modules";
import myLogger from './middlewares/myLogger';


const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
const store = createStore(rootReducer,applyMiddleware(myLogger));
console.log(store.getState());
root.render(
  <StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </StrictMode>
);

applyMiddlewareimport 해서 createstore안에 넣어주고 사용할 미들웨어를 파라미터로 넣어준다.

 

 

콘솔을 확인해 보면 어떤 액션이 들어가고 상태값이 어떻게 변하는지 미들웨어에서 출력을 해준다

이렇게 리듀서로 들어가는 자료들을 중간에서 받아서 출력해 줄 수도 있고 변경해서 다시 보내줄 수도 있는 게 미들웨어의 역할이다.

 

 

만들어진 미들웨어 써보기

redux-logger

npm install --save react-redux

redux-logger는 만들어져 있는 미들웨어이며 이전상태값과 액션 다음상태값을 출력해준다.

 

원래 저기에 이전상태값이랑 action객체 다음 상태값이 다 떠야되는데 왜 안뜨는건지... 

logger콘솔화면

원래는 이렇게 상태값과 액션객체가 뜬다.

 

 

피드백

사실 미들웨어는 저번주 금요일에 배웠던 개념인데 이해가 너무안되서 정리를 좀더 해보고 오늘 학원에서도 다시해보고 thunk를 배우면서 어느정도 개념에 대해서 받아들여진것같다. 역시 코딩은 안되면 일단 반복하면 되는구나.. 

다음 포스팅은 thunk에 대해서 할것같은데 이것도 아직 제대로 알아먹은건아니라서 두루뭉술하게 될지도. 일단 인강이나 이런거 찾아보고 내 뇌속의 개념을 조금더 보충해서 알아보기쉬운 포스팅을 쓸려고 하고있다. 그냥 코드만 따라하는건 아무나 하는거고 코드를 보고 이해할수있는게 중요한것같다. 이제 포트폴리오 준비도 해야되고 정신도 없지만 . 배우는 개념들은 모두 놓치지않고 이해하고싶다.

반응형
반응형

여기까지가 어제 구현 한 부분이다

modules에서 redux모듈counter.jstodos.js를 만들고 index.js에서 combinedReducers로 합쳐서 rootReducer를 만들어 준 후에 rootReducer를 이용해서 store를 만들어주고

만들어진 store를 컨테이너컴포넌트인 CounterContainers.js 에서 접근해서 상태값과 디스패치를 받아서

프레젠테이션컴포넌트인 Counter.js에게 props로 필요한 값을 전달해서

상태값dispatch함수를 화면구현에 사용했다.

 

오늘은 여기에 저번에 Redux모듈로 만들어놓고 사용하지 않은 todos를 이용하는 todolist를 만들어주겠다

 

화면을 구성하는 요소인 프레젠테이션 컴포넌트부터 만들었다.

 

components / Todos.js

import React, { useState } from 'react';
import Todolist from './Todolist';

const Todos = ({onCreate,onToggle,todos}) => {
    const [text,setText] = useState("") //input에 들어갈 상태값.
    const onChange = (e) =>setText(e.target.value) //input태그에 값이 입력되면 상태값이변함
    const onClick = () =>{
        onCreate(text);
        /*
        (text) =>({
        	type:ADD_TODO,
        	todo:{id:nextId,text: text,done:false}
    	}) 
        */
        setText(''); // 등록한후에는 input창을 초기화하기위해서 상태값 비워줌
    }
    return (
        <div>
            <div>
                <input value={text} onChange={onChange}></input>
                <button onClick={onClick}>등록</button> 
            </div>
                <Todolist onToggle={onToggle} todos={todos}/>
        </div>
    );
};

export default Todos;

인풋과 등록창을 만들어주고 등록되었을때 화면에 뜨는 부분은 Todolist컴포넌트로 따로 만들었다.

input 태그에도 상태값을 하나 추가로 주기위해 따로 useState를 이용해서 상태값을 만들어줬다.

 

이제 할일을 추가했을 때 띄워줄 Todolist컴포넌트를 만들어준다.

 

components / Todolist.js

import React from 'react';

const Todolist = ({todos,onToggle}) => {
    return (
        <div>
            <ul>
                {todos.map(todo => <li key={todo.id} 
                onClick={()=>onToggle(todo.id)} 
                style={{textDecoration: todo.done ? 'line-through':'none'}}>
                    {todo.text}
                </li>)}
            </ul>
        </div>
    );
};

export default Todolist;

Todos컴포넌트에서 onClick해주면 상태값의 todos에 저장된다.

case ADD_TODO:
   return[
      ...state, //원래있던값들을 저장하고
      action.todo // todo:{id:nextId,text: text , done:false} 새로운 todo추가 
    ]

todosTodolist.js에 넘겨주고 배열메서드인 map으로 <li></li> 안에 값을 넣어서 만들어준다. 

li를 클릭하면 isDone이 토글되고

isDone이 false일 때는 유지하고 true가 되면 밑줄을 그어주도록 스타일도 적용해 준다.

style={{textDecoration: todo.done ? 'line-through':'none'}}

 

isDone을 토글 시켜줄 onToggle TodosContainer에서 만들어서 전달된다.

onToggle아이디를 전달받아서

case TOGGLE_TODO:
     return state.map(todo => todo.id === action.id ? {...todo, done:!todo.done} : todo )
default:

todos를 다시 맵으로 돌려서 해당하는 id와 같은 아이디가 있으면 todo.done을 토글 시켜준다.

 

 

 

어제 했던 redux를 이어서 한 건데 코드를 한번 더 읽어보고 다시 써보니까 이제 동작원리가 조금은 이해가 되는 것 같다.

여기저기서 불러쓰는 게 많아서 복잡해보였는데 불러서 쓰는 요소들을 밑에 주석으로 써가면서 보니까 읽기에도 편하고 뭐하는 함수였는지 바로바로 알수있었다. 주석은 좀 더 간결하게 쓰는게 좋을 것 같지만 일단은 내가 이해를 해야 하니 길어도 어쩔 수 없다..ㅋㅋㅋ

반응형
반응형

오늘은 react에서 상태를 관리해 주는 기술react-redux를 배웠다.

 

Redux

 

Redux 시작하기 | Redux

소개 > 시작하기: Redux를 배우고 사용하기 위한 자료

ko.redux.js.org

Redux(리덕스)는 JavaScript(자바스트립트) 상태관리 라이브러리이다.

(react에서뿐만 아니라 바닐라 자바스크립트에서도 사용가능)

 

redux의 규칙 3가지

1. 하나의 애플리케이션 안에는 하나의 스토어가 있다.

2. 상태는 읽기 전용이다.

3. 리듀서는 순수한 함수여야 한다.

 

redux사용방법

//스토어 생성하기
const sotre = Redux.createStore(리듀서함수)
redux작동 그래프

액션 객체를 dispatch로 보내주면 dispatch는 스토어에 있는 reducer함수를 불러서

함수에 액션객체를 매개변수로 새로운 상태값을 반환해 준다.

 

1. 액션객채(Action)

상태를 업데이트할 때 액션을 전달해 준다.

액션은 객체로 표현되며 type속성을 가지고 있다.

{
	type:"INCREMENT"
}

2. 액션 생성함수(Action creator)

액션객체를  퉤! 하고 뱉어주는 함수

function increment(add){
	return{
		type:"INCREMENT",
		add: add
	}
}

useReducer에서도 액션을 사용했지만 액션을 함수로 만들어서 사용한 적은 없었는데.

이렇게 사용하면 동일한 액션객체를 전달해줄 수 있고 매개변수를 받아서 액션객체에 추가해 줄 수도 있다.

 

3. 리듀서(reducer)

상태를 업데이트시켜주는 함수이다.

리듀서는 두 가지 파라미터를 받아온다.( 상태값, 액션객체 )

function reducer(state,action){
	return newState;
}

리듀서에서는 새로운 상태값을 리턴해준다.

 

4. 스토어(store)

리덕스에서는 한  애플리케이션당 하나의 스토어를 만든다.

스토어 안에는 현재의 상태와 리듀서 내장함수들이 들어가 있다.

dispatch(), subscribe(), getState()

 

5. 구독(subscribe)

스토어의 내장함수 중 하나이다. 함수 형태의 값을 파라미터로 받아오며 subscribe함수에

특정 함수를 전달하면 액션이 디스패치 될 때마다 전달해 준 함수가 호출됨.

//자바스크립트에서는 상태가 변해도 리렌더링 되지 않기 때문에 상태값이 변할 때 함수를 다시 호출해서 바뀐 값을 다시 넣어서 실행해줘야 한다.

 

 

여기서 redux를 가져올 주소를 복사해서 redux를 사용할 파일에 연결해 준다.

<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.2.0/redux.min.js"></script>

이제 redux의 기능들을 해당 애플리케이션 파일에서 사용할 수 있다.

redux의 필요성을 알아보기 위해 같은 기능을

redux를 사용하지 않고 구현한 코드와 사용해서 구현한 코드 두 개를 쓰겠다.

 

withoutredux.html (redux 없이)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    
    <style>
        .component{
            border: 5px solid #000;
            padding:10px;
        }
    </style>
</head>
<body>
    <div id="red"></div>
    <div id="blue"></div>
    <script>
        function red(){
            document.querySelector("#red").innerHTML = `
            <div class="component">
                <h1>red</h1>
                <button onclick="
                document.querySelector('#red').style.backgroundColor='red'
                document.querySelector('#blue').style.backgroundColor='red' ">버튼</button>    
            </div>
            `
        }    
        function blue(){
            document.querySelector("#blue").innerHTML = `
            <div class="component">
                <h1>blue</h1>
                <button onclick="
                document.querySelector('#blue').style.backgroundColor='blue'
                document.querySelector('#red').style.backgroundColor='blue'">버튼</button>    
            </div>
            `
        }  

        red();
        blue();  

        </script>
</body>
</html>

<div> 태그를 두 개 만들어주고 아래에서 자바스크립트로 div태그 안에 들어갈 요소들을 만들어주고

버튼에는 이벤트를 만들어 주었다. 

red 쪽에 있는 버튼을 클릭하면 div두 개의 배경색이 빨간색으로 변하고 

blue 쪽에 있는 버튼을 클릭하면 div 두 개의 배경색이 파란색으로 변한다.

버튼을 클릭하면 배경색이 변한다.

 이 코드에서 div를 추가해서 yellow를 하나 더 만들어 준다고 가정하면

        function yellow(){
            document.querySelector("#yellow").innerHTML = `
            <div class="component">
                <h1>blue</h1>
                <button onclick="document.querySelector('#blue').style.backgroundColor='yellow'
                document.querySelector('#red').style.backgroundColor='yellow'
                 document.querySelector('#yellow').style.backgroundColor='yellow'
                ">버튼</button>    
            </div>
            `
        }

이런 함수를 하나 추가해줘야 하고 위의 redblue 함수도 yellow박스에 색이 들어갈 수 있도록

yellow div에 배경색을 주는 코드를 한 줄 추가해줘야 한다 이렇게 하나의 태그가 늘어날 때 다른 함수들도 다 변경되어야 하는 관련성이 있다.

 

redux를 사용하면 이런 관련성을 낮춰줄 수 있다.

 

withredux.html (redux를 사용)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.2.0/redux.min.js"></script>
    <style>
        .component{
            border: 5px solid #000;
            padding:10px;
        }
    </style>
</head>
<body>
    <div id="red"></div>
    <div id="blue"></div>
    <script>
        //1.리듀서 함수 만들기
        function reducer(state,action){
            //state초기값을 위해 처음에 호출
            if(state === undefined){
                return {color:"white"}
            }
            let newState;
            if(action.type === "CHANGE_COLOR"){
                newState={...state , color:action.color}
                console.log(newState)
            }
            return newState;
        }
        // 2. redux스토어 생성하기.
        const store = Redux.createStore(reducer);
        
        function red(){
            let state = store.getState();// 상태값 반환
            document.querySelector("#red").innerHTML = `
            <div class="component" style="background-color:${state.color}">
                <h1>red</h1>
                <button onclick="store.dispatch({type:'CHANGE_COLOR',color:'red'})">
                버튼</button>    
            </div>
            `
        }    
        function blue(){
            let state = store.getState();// 상태값 반환
            document.querySelector("#blue").innerHTML = `
            <div class="component" style="background-color:${state.color}">
                <h1>blue</h1>
                <button onclick="store.dispatch({type:'CHANGE_COLOR',color:'blue'})">
                버튼</button>    
            </div>
            `
        }    

        //구독하기
        store.subscribe(red); //상태가업데이트될때 해당함수를 다시 호출
        store.subscribe(blue);
        red();
        blue()
    </script>
    
</body>
</html>

이렇게 써주면 아까 리덕스를 쓰지 않고 만들었던 코드와 똑같은 기능을 할 수 있게 만들어졌다.

여기서는 새로운 div를 추가해 줘도 다른 함수를 수정해주지 않아도 된다.

 

yellow div 추가

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.2.0/redux.min.js"></script>
    <style>
        .component{
            border: 5px solid #000;
            padding:10px;
        }
    </style>
</head>
<body>
    <div id="red"></div>
    <div id="blue"></div>
    <div id="yellow"></div>
    <script>
        //1.리듀서 함수 만들기
        function reducer(state,action){
            //state초기값을 위해 처음에 호출
            if(state === undefined){
                return {color:"white"}
            }
            let newState;
            if(action.type === "CHANGE_COLOR"){
                newState={...state , color:action.color}
                //  newState = Object.assign({},state,{color:action.color}) // object.assign 객체 복사 ({복사될대상},복사할객체,추가할내용)
                console.log(newState)
            }
            return newState;
        }
        // 2. redux스토어 생성하기.
        const store = Redux.createStore(reducer);
        
        function red(){
            let state = store.getState();// 상태값 반환
            document.querySelector("#red").innerHTML = `
            <div class="component" style="background-color:${state.color}">
                <h1>red</h1>
                <button onclick="store.dispatch({type:'CHANGE_COLOR',color:'red'})">
                버튼</button>    
            </div>
            `
        }    
        function blue(){
            let state = store.getState();// 상태값 반환
            document.querySelector("#blue").innerHTML = `
            <div class="component" style="background-color:${state.color}">
                <h1>blue</h1>
                <button onclick="store.dispatch({type:'CHANGE_COLOR',color:'blue'})">
                버튼</button>    
            </div>
            `
        }    
        function yellow(){
            let state = store.getState();// 상태값 반환
            document.querySelector("#yellow").innerHTML = `
            <div class="component" style="background-color:${state.color}">
                <h1>yellow</h1>
                <button onclick="store.dispatch({type:'CHANGE_COLOR',color:'yellow'})">
                버튼</button>    
            </div>
            `
        }    



        //구독하기
        store.subscribe(red); //상태가업데이트될때 해당함수를 다시 호출
        store.subscribe(blue);
        store.subscribe(yellow);
        red();
        blue();
        yellow();
    </script>
    
</body>
</html>

 

 

 

이제 리액트에서 redux를 사용해 보자

 

React에서 redux사용하기

 

redux, react-redux 설치하기

npm install redux
npm install react-redux

 

redux사용법 

스토어 생성하기

//createStore 불러오기
import { legacy_createStore as createStore } from 'redux';
//store 만들기
const store = createStore(리듀서함수)

 

스토어 사용하기

스토어를 사용하려면 상위컴포넌트에서 Provider로 감싸줘야 하위 컴포넌트에서 store를 불러서 쓸 수 있다.

import { Provider } from 'react-redux';

<Provider store={store}>
   <App />
</Provider>

 

* 리덕스 스토어 상태 조회하는 Hook함수 useSelector

import { useSelector } from 'react-redux";

const state = useSelector(state=>state)

* 리덕스 스토어 디스패치 반환하는 Hook함수 useDispatch

import { useDispatch } from 'react-redux";

const dispatch = useDispatch()

​이렇게 어디서든 디스패치와 상태값을 불러서 사용할 수 있다.

 

예제 만들기

리덕스 모듈 생성 후 스토어 생성하기

리덕스 모듈이란 액션 타입, 액션생성함수, 리듀서 가 모두 들어있는 자바스크립트 파일.

여러 개의 리덕스 모듈을 생성하여 하나의 리덕스 모듈로 합쳐서 사용한다.

* combineReducers({ 리덕스모듈 객체 }) 함수를 사용하여 리덕스 모듈을 합쳐줌.

import { combineReducers } from "redux";
const rootReducer = combineReducers({
    리덕스모듈1: 리덕스모듈1,
    리덕스모듈2: 리덕스모듈2
}) ---> 리듀서를 합쳐줌

counter 모듈 + todos 모듈-----> 루트리듀서 ----> 스토어 생성.

 

주의할 점

액션 타입 - 다른 리덕스 모듈과 겹치지 않게 하기 위해 컴포넌트 이름의 접두사를 앞에 붙여줘야 한다

counter/SET_DIFF

액션 생성함수 -액션객체를 리턴해주는 함수. (export로 내보내기)

리듀서 - 컴포넌트 이름으로 만들어지며 state 파라미터에 디폴트 초기값을 지정합니다.

(export default로 내보내기)

state=initialState

 

모듈들을 관리해 줄 modules폴더를 만들고 그 안에 모듈들을 만들어준다.

 

modules/counter.js

//액션 : 타입 만들기
const SET_DIFF =  "counter/SET_DIFF";
const INCREMENT = "counter/INCREMENT";
const DECREMENT = "counter/DECREMENT";

//액션 생성 함수 만들기
export const setDIFF = (diff)=>({type:SET_DIFF,diff});
export const increase = () =>({type:INCREMENT});
export const decrease = () =>({type:DECREMENT});
//초기 상태 선언
const initialState = {
    number: 0 ,
    diff: 1
}
//리듀서 선언
export default function counter(state=initialState , action){
    switch(action.type){
        case SET_DIFF:
            return{
                ...state,
                diff:action.diff
            }
        case INCREMENT:
            return{
                ...state,
                number:state.number + state.diff
            }
        case DECREMENT:
            return{
                ...state,
                number:state.number - state.diff
            }
        default:
            return state;
    }
}

 

modules/todos.js

//액션타입선언
const ADD_TODO = 'todos/ADD_TODO';
const TOGGLE_TODO = 'todos/TOGGLE_TODO';

//액션 생성 함수
let nextId = 1
export const addTodo = (text) =>({
    type:ADD_TODO,
    todo:{id:nextId,text: text,done:false}
})
export const toggleTodo = (id)=>({
    type:TOGGLE_TODO,
    id:id
})

//초기상태값
//초기 상태는 배열이어도 되고,원시타입(숫자,불린,문자열) 객체도 가능하다.
const initialState = [
    // {
    //     id:1,
    //     text:"해야할일",
    //     done:false
    // }
]
//리듀서

export default function todos(state=initialState,action){
    switch(action.type){
        case ADD_TODO:
            return[
                ...state,
                action.todo
            ]
        case TOGGLE_TODO:
            return state.map(todo => todo.id === action.id ? {...todo, done:!todo.done} : todo )
        default:
            return state
    }
}

 

​modules/index.js  rootreducer 만들기

import { combineReducers } from "redux";
import counter from "./counter";
import todos from "./todos";

//한프로젝트에 리듀서가 여러개일때 하나로 합쳐서 사용 => rootreducer 루트리듀서
//combinereducers( )

const rootReducer = combineReducers(
    {
        counter:counter,
        todos:todos
    }
    )
export default rootReducer

 

스토어 생성하기

src/index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { legacy_createStore as createStore } from 'redux';
import rootReducer from './modules';
import { Provider } from 'react-redux';
import { devToolsEnhancer } from '@redux-devtools/extension'; // 크롬확장 redux devtools
//스토어 만들기
const store = createStore(rootReducer,devToolsEnhancer());

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

 

store를 만들고 Provider로 묶어줘야 하위 컴포넌트에서 store요소를 불러서 사용할 수 있다.

이제 이 값들을 불러서 화면을 구성하고 상태값을 변경해 줄 컴포넌트를 만들어주면 된다.

 

컴포넌트 만들기


1. 프레젠테이셔널 컴포넌트 

실제 보이는 태그들을 만들어주는 컴포넌트, redux스토어에 직접 접근하지 않음
필요한 값은 props로 받아와서 사용하는 컴포넌트, 주로 UI를 선언하는 것에 집중

 

2. 컨테이너 컴포넌트

 

프레젠테이셔널 컴포넌트를 감싸고 store에 접근해서 값을 props로 프레젠테이셔널로 전달.
리덕스 스토어의 상태를 조회하거나, 액션을 디스패치 할 수 있는 컴포넌트.
프리젠테이셔널 컴포넌트를 불러와서 사용

 

꼭 이렇게 만들어줄 필요는 없지만 기능적으로 분리해 주면 나중에 에러가 났을 때 찾기 편하다

 

1. 프레젠테이셔널 컴포넌트

components/Counter.js

import React from 'react';

const Counter = ({number,diff,onIncrease,onDecrease,onsetDIFF}) => {
    const onChange = (e)=>{
        onsetDIFF(Number(e.target.value)) //(diff)=>({type:SET_DIFF,diff});
    }
    return (
        <div>
            <h1>{number}</h1>
            <div>
                <input type="number" value={diff} min="1" onChange={onChange}/>
                <button onClick={onIncrease}>+</button>
                <button onClick={onDecrease}>-</button>

            </div>
        </div>
    );
};

export default Counter;

 화면을 구성해 주는 요소들이 들어있고 필요한 값들은 props로 컨테이너 컴포넌트한테서 받아온다.

 

2. 컨테이너 컴포넌트

containers/CounterContainer.js

import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import Counter from '../components/Counter';
import { decrease, increase,setDIFF } from '../modules/counter';

const CounterContainer = () => {
    //useSelector() 는 리덕스스토어의 상태를 조회하는 hook이다

    const { number,diff } = useSelector(state=>state.counter);
    const dispatch = useDispatch();
    // 각 액션들을 디스패치 하는 함수
    const onIncrease = ()=> dispatch(increase());
    const onDecrease = ()=>dispatch(decrease());
    const onsetDIFF = (diff) => dispatch(setDIFF(diff));
    return (
        <Counter number={number} diff={diff} onIncrease={onIncrease} onDecrease={onDecrease} onsetDIFF={onsetDIFF}/>
    );
};

export default CounterContainer;

 

컨테이너 컴포넌트에서 Counter컴포넌트를 불러서 사용하고 Props로

함수=dispatch(액션생성함수)와 상태값을 보내주고 있다.

 

App.js에서 CounterContainer 컴포넌트를 불러서 사용하면 끝

 

redux자체는 그렇게 되게 어렵지는 않은데 이번에 redux를 배우면서 새로운 개념들을 같이 배워서 이해하기가 정말 너무 힘들었다. 모듈을 다 나눠서 만들고 합쳐서 하나로 만들고 액션객체도 일일이 만들어줬었는데 이번에는 액션객체를 만드는 함수를 만들어서 사용하니 갑자기 연결된 애들이 많아져서 뭐가 어디서 불러서 쓰고 어디에 들어간게 맞는건지 구분을 못해서 수업시간에 좀 힘들었다.. 그래도 redux는 많이 사용하고 있다고하니 연습해서 꼭 잘 쓰고싶다.. 포기하지말자.. 수료 2달남았다.. ㅠㅠ

반응형

+ Recent posts