리액트로 간단한 뉴스 페이지 구현

제이미·2024년 9월 25일
0

리액트

목록 보기
11/19
post-thumbnail

네이버 블로그에 적었던 내용을 옮기는 글

영문 뉴스 오픈 API를 사용해서, 뉴스를 패치하고 검색창과 캘린더를 삽입하여 필터링을 하는 기능 구현을 한번 해보려고 시작!

"먼저 검색창부터 넣어보자"

input에 클릭했을 때, 겉에 보이는 하이라이트 색상이 뜨는게 맘에 들지 않는다

  • css에 outline: none; 으로 해결

"그 다음 캘린더를 넣어보자. 어떻게 달력을 가져올 수 있을까?"
날짜를 선택할 수 있는 react-datepicker 라이브러리 사용해보자

npm으로 datepicker를 설치하고 import한 후 return에 컴포넌트 사용이 가능했다!

date의 state를 만들어서 selected에 오늘로 초기 상태가 정의된 date를 넣어주고, 다른 날짜를 선택했을 때 상태를 바꿔주는 dateChangeHanlder 함수를 만들어 넣어줬다

"상태 관리를 어떻게 해야할까?"
작은 컴포넌트 구현을 하는 중이지만 전역 상태 관리가 궁금해졌다
많이 사용된다고 들었던 리덕스와 리덕스 툴킷을 한번 사용해보기로 결심!

리액트 리덕스와 리덕스 툴킷을 설치 먼저 했다
리듀서 파일에 newsSlice를 정의해주고,
구글링으로 어떻게 store를 셋업해야 하는지 찾아서 설정해봤다! - 리듀서들을 index store에 모두 넣어주기
(물론 index.js의 Provider에다가 store를 전해주고 을 감싸주어야 전역 상태 관리가 가능하다)

이제 오픈 API에서 뉴스를 가져오는 요청을 하려 한다
(과거 axios를 접하기 전 fetch를 썼으므로, 해당 코드에서는 fetch를 사용)
받았던 인증키를 사용하여, get 요청을 api 주소로 하는 함수를 호출하고, news의 상태를 새로 업데이트 한다

"리듀서의 상태를 news 컴포넌트에서 불러와보자!"
useSelector를 import 먼저 해줘야 하고, 이름에 정의해주기

이 과정에서 실수를 하게 되었는데, useSelector로 news를 불러올 때 state.news까지만 써서 제대로 원하는 데이터를 못 얻었다

초기에는 initialState 객체 안에 news라는 state만 있으니, state(store).news(store에 저장한 리듀서 이름).news(해당 리듀서 안에 필요한 상태 이름)로 작성함으로써 해결!

"아까 news 리듀서 파일 내에 정의해뒀던, 뉴스를 패치하는 함수는 어떻게 사용할 수 있을까?"
useDispatch를 사용해서 dispatch(정의한함수) 로 호출할 수 있다!
나는 이 페이지를 들어오자마자 뉴스를 패치하고 싶었기에, useEffect 내에서 뉴스 패치 함수를 호출해줬음

"근데, 확인해보니 api에서 가져온 뉴스 데이터의 날짜가 ISO date String이었다"
이걸 우리가 읽기 쉬운 date 형태로 바꾸어주기 위해 new Date()을 사용했음, new Date을 사용하면 객체가 되기 때문에 toLocaleDateString()으로 날짜를 다시 스트링 형태로 바꿔주고 화면에 뿌려줬다

"그 다음 캘린더 날짜로 인한, 뉴스 필터링을 해보도록 하자"
datepicker로 선택된 날짜와 뉴스의 날짜를 비교하기 위해, datepicker 형태를 위에 바꾼 뉴스 날짜 형태랑 같게 만들어줌

new Date() 객체를 getMonth(), getDate(), getFullYear()를 이용해 원하는 달,날짜,연도를 뽑을 수 있음

datepicker로 가져온 스트링 형태로 바꾼 date과, 그와 같은 형태로 바꾼 뉴스 날짜를 비교해야 한다
date 필터 기능을 하기 위해, date filter 함수를 리듀서 안에 만들어 줌

초반에 initialState의 news State를 filter하고 나서의 값으로 바꿔준다
하지만 여기서 문제 :(
"필터된 state가 이니셜 스테이트로 바뀌어버려, 다음 날짜가 바뀌었을 때 원하는 뉴스를 볼 수 없게 되었다"

필터를 한 후 news slice에 dateFilteredNews state를 추가 생성해 그곳에 필터 뉴스를 넣어줌으로써 해결

"여기서 또 문제가 생겨버렸다!"
useEffect 내에서 newsActions.checkDateFiltered(true)로 셋하는 dispatch가 먹지 않는 중

  • slice에서 이니셜스테이트를 false로 해뒀지만, 렌더 후 필터를 하지 않았음에도 true로 변해버림
  • 날짜를 바꾸지 않았음에도, 날짜를 바꾼 걸로 인식 해 전체 뉴스를 보여주지 않음(날짜를 바꿨을 때만, 실행하게 하고 싶다)

어떻게 해결을 했냐면,
useRef를 사용해 처음 렌더할 때의 초기 date값을 저장해줬다. 그리고 date state이 바뀌었을때 ref의 초기값과 비교해서 다른 날짜가 되었다면 checkDateFiltered라는 상태를 true로 바꿔줬다!

이로 인해, ref로 초기값을 저장할 수 있는 것을 깨달았다(ref는 리렌더를 하지 않으므로, 맨 처음에 초기값을 저장할 수 있음)

"이제 검색창으로 필터링 하는 기능을 만들 때가 되었다!"
검색된 키워드를 바탕으로 쿼리를 날려주려고 했다

쿼리 스트링으로 검색 키워드의 news api를 가져옴으로써 패치 성공 :)
-> api 주소에서 q=${searchedWord}를 사용

검색창에 뉴스 키워드 중 하나를 입력해 그에 맞는 뉴스가 searchedNews state 배열 안에 잘 들어왔는지 확인을 브라우저에 해본다
(Sunset을 검색 해봤음)

오예 Sunset이 들어간 제목의 뉴스 데이터만을 받을 수 있었다~

아무런 필터가 적용되지 않았을 때의 전체 뉴스(한 눈에 보기 쉽게 하기 위해, 소량의 뉴스 api로 설정)

검색창에 키워드를 검색해서, 그에 맞는 뉴스만 보여주기

캘린더에서 날짜를 클릭함으로써, 그에 맞는 날짜의 뉴스만 보여주기

이로써, 뉴스 오픈 API를 이용하여 검색창과 캘린더의 필터링을 하는 페이지를 구현해봤다!
생각만 했을 때는 엄청 쉬울 줄 알고 껌이지~ 했는데,
오 생각보다 막히는 부분들이 꽤 생겼었다 :(
그래.. 무시하다 큰 코 다치는 일이지(절대 자만하지 말아라)

profile
프론트엔드 개발하다 궁금할 때

0개의 댓글