👩‍💻todo 앱을 만들어보자❗

1️⃣

📁recoil-todo-app 폴더 만들기

2️⃣

📥npx create-react-app ./ 으로 리액트 설치하기

3️⃣

npm run start로 리액트 앱 실행하기

3️⃣

▫ src>App.js

필요없는 부분 지우고

📥리코일 사용해야 하니까 npm install recoil 명령어 입력해서 설치하기


🐍index.js 에서 👩‍🦱부모 컴포넌트 AppRecoilRoot로 감싸주기

▫ src>index.js

▫ src>App.js

todo 앱에 필요한 값을 담아주기 위해 원래는 이렇게 해서
기본 값을 배열 [ ]로 준 담에 하나의 todo 마다
하나의 객체가 todo가 늘어날때마다 저렇게 됐었음

저렇게 할 수도 있지만 지금은 '리코일' 사용하고 있으므로
저부분을 state가 아닌 atom 이용할거임

아톰

🌫🐱‍🏍아톰을 위한 파일 만들기

▫ src>TodoAtoms.js

atom 생성할 때 어떤게 필요할까❓➡key & default ( initalvalue 초기값 )👌

default 값은 [ ] 이거임

todoListState 다른 곳에서도 사용하니까 export로 내보내기🥏

이젠 App.js 에서 state 필요없으니 삭제하기👋

이러한 todo 앱을 만들건데 input에 입력하고 Add 버튼 누르면
리스트 하나씩 추가되는 부분을 위해 컴포넌트 하나 만들기

▫ src>components>TodoItemCreator.js

👩‍🦱App.js( 부모 ), 👩TodoItemCreator.js( 자녀 )

여기서 타이핑한 값을 TodoItemCreator 컴포넌트에서만 기억해주고 싶으면❓

✅타이핑한 값은 여기 컴포넌트 내에서만 사용할거임

다른 곳과 다른 컴포넌트에서도 갖고 있어야하는 값이면
상태 관리하는 곳에다가 넣어 쓰면 되지만
그 값이 TodoItemCreator 내에서만 기억하고 있어야하는 값이면 state 사용🙆‍♀️

⌨타이핑 하려고 하면 타이핑이 안 되는건 왜 그러는 걸까❓

onChange 해서 setInputValue로 업데이트 해줘야 함
지금은 타이핑 하더라도 계속 value가 초기값인 빈 문자열 ' ' 이라서 안 바뀌는 것❗

여기서 e.target이 뭐지❓

e.target.value 하면 우리가 타이핑하는 값
e.target 까지만 하면 이벤트( e )가 발생하는 target이니까
현재 이벤트가 발생하는 곳은 input인 것🔥

이젠 타이핑 잘 되는 걸 볼 수 있음👀


Add 버튼 누르면 리스트가 추가되게 하기

button 태그 안에 onClick 넣어주고 addItem 이라는 함수 만들기

input 안에 '밥먹기' 입력 후 Add 버튼 누르면 어떠한 데이터를 어디다 넣어줘야할까❓❗
👉 객체( id 값, 밥먹기 완료한 상태면 completedtrue로 되어야함 )

✅이 객체를 담고 있을 배열이 필요 ( TodoAtoms.js 안에 있음 )

[ ] 안에다 값을 넣어줘야하는데 그걸

여기서 해줄거임

todoListState를 업데이트 해주는 setter 함수만 필요⭕

useSetRecoilState( 이 안에 recoilState를 넣어줘야 함 )

#️⃣유니크한 id 주기 위해 따로 만듦

...oldTodoList : 원래 있는 리스트들
getId( ) : 0, 1, 2,... id가 유니크하게 생성됨

textinput에 타이핑한 값이 들어가야하므로 inputValue
isComplete는 첨에 체크 안 된 상태여야 하니까 당연히 false로 해주면 됨

작성했던 밥먹기 지워야하니까 setInputValue 이용해서

이렇게 지워주면 됨


➕추가 된 걸 화면에 보여주기

여기 있는 이 값을

여기로 가져오고 싶으면 어떻게 해야할까❓

값만 가져올 땐 useRecoilValue 하면 됨❗

todoList가 배열이니까 🗺 map 메서드 써서 순회

이부분을 위해

components 폴더 안에 TodoItem.js를 만들어줄 것
rafce 해서 함수형 컴포넌트 자동 생성하기

만들어준 TodoItem 컴포넌트 map 메서드 안에 넣어주고
당연히 key 값 필요하니까 넣고 전체 객체 데이터 item 이라는 이름으로 todoItem

▫ src>components>TodoItem.js

input 2개랑 버튼 하나 만들기

운동하기 input에 입력하고 Add 버튼 누르면 위처럼 생성됨

'밥먹기' '운동하기' 까지 나오길 원하는데 그럴려면 어떻게 해야할까❓

여기서 올바른 값을 내려주고 있음

item 받아와서 value 안에 item.text 넣어주면 됨

잘 나오는 걸 확인할 수 있음👀

이부분들은 타이핑 안 됨
input을 누른다 하더라도 item.text 값이 변경되는 게 아니기 때문

checked={ item.isComplete } 하면 체크된 상태로 나옴


🙋‍♀️토글 기능 추가

위에서 만들어준 함수를 집어넣고 ( 이 안에 첫번째로 들어가는 게 arr )

arr : 현재의 모든 TodoList를 넣어줄 것

🤓useRecoilStateTodoAtoms.js 에 있는 todoListState 가져오기

arr 필요하다고 했으니 todoList 넣어주고

그 담은 index 넣어줘야함

index를 구하려고 하는 것

findIndex : 첫번째로 찾은 인덱스를 리턴🔁

todoList 배열에서 todoList 하나의 객체 데이터( listItem )를
listItem 이랑 현재 item 하고 같은 걸 찾아서 itemindex를 리턴하는 것


❌리스트 삭제하기

저걸 삭제하면 해당 인덱스 1번 저부분이 삭제되는 것

만약, 첫번째 index를 삭제한다면❓

...arr.slice(0, 1) : 전체 리스트에서 0번째만 슬라이스,
...arr.slice(index(1) + 1) : index 1이니까 1 + 1 = 2
👉 전체 index 에서 0번째 2번째 제외하고 1번째만 남게 됨💡

❌누르면 해당 리스트 삭제되는 걸 확인할 수 있음👀


✏ 리스트 input 수정하기

밥먹기 하고 Add 눌러서 추가하면 수정이 안 됨

타이핑 잘 되는 걸 확인할 수 있음👀


🙂Filter 기능 추가하기

▫ src>TodoAtoms.js

atom 하나 더 만들기

어떤 값에 의존해서 어떠한 값을 보여주겠다 하는 건➡selector 사용🔥

ex ) 어떠한 값을 타이핑할 때 타이핑한 값에 의존해서
text.length 값을 보여줄 때 selector 사용했었음

저 두개 의존해서 필터링 되는 값들만 보여줄거라 selector 사용할 것🧐

의존 하는 todoListStatetodoListFilterState 값을 가져오고 싶으면❓

get 사용, todoListState 배열 리스트를 list 안에 넣어둔거임

todoListFilterState는 첨에

All로 해놨으면

Show All 이고
다른 옵션 클릭하면 Show Completed 라고 할거임

이렇게 세가지 조건으로 줄 것

const list = get(todoListState);[ ] 배열이고

const filter = get(todoListFilterState);
'Show All' | 'Show Completed' | 'Show Uncompleted' 3개 중 하나임

여기는 리듀서 부분이랑 비슷하게 로직 짜면 됨

'Show All'일 땐 어떤식으로 해주고 'Show Completed'일 땐 어떻게 해주고
'Show Uncompleted'일 땐 이렇게 해주고 이부분을 switch 문으로 처리해주기😶

filterTodoListState 다른 곳에서도 쓰일 거니까 export로 내보내기🥏

이걸 이용해서 여기 값들을 보여주고 싶음

지금은 이걸 이용해서 보여주고 있는 것
필터링 된 게 아닌 항상 모든 리스트만 보여주고 있는거임😐

이부분 부터 만들어보자❗

components 폴더 안에 TodoListFilters.js 파일을 만들고
rafce 함수형 컴포넌트 자동 생성하기

TodoListFilters.js 파일 만들었으니까
App.js 안에 TodoListFilters 컴포넌트 넣어주기

잘 뜨는 걸 확인할 수 있음👀

▫ src>components>TodoListFilters.js

valueAll➡'Show All', Completed➡'Show Completed',
Uncompleted➡'Show Uncompleted'로 해줘야함

🖱옵션 클릭했을 때 어떤 걸 클릭하고 있는지 이 컴포넌트에서 기억하고 있어야함🧠

🖱Show Uncompleted 옵션 클릭했을 경우
todoListFilterState default 값이 'Show Uncompleted'가 돼야함🔄

🤐여기서 어떻게 해야지 todoListFilterState가 바뀔까❓

select의 기본값이 'Show All'이 되게 해야함

왜냐, 첨에 새로고침 했을 때 All로 나와야하기 때문❗

TodoAtoms.js 안에 있는 todoListFilterState 값 가져오기
👉 const [filter, setFilter] = useRecoilState(todoListFilterState);

새로고침 해도 All
문제는 다른 옵션 클릭해도 반영안 됨 ( 안 바뀜🙅‍♀️ )

🔄다른 옵션 변경 되게 하려면 어떻게 해야할까❓

🏷 select 태그 안에 onChange={updateFilter}updateFilter 함수 만들기

e.target.value 구조분해할당 하면 event 안에 target이니까 target 🔥

value 라는 변수를 바로 가져오고 싶으면 지금하면 target.value니까
한 번 더 구조분해 해서 { target: { value } } 이렇게 해주면 됨🙆‍♀️

이젠 선택한 옵션이 잘 바뀌는 걸 확인할 수 있음👀


🧐옵션 선택하면 옵션에 맞게 필터링 되게 하기

All로 했다가 input에 '밥먹기' '운동하기' '공부하기' 입력하고
Add로 하나씩 리스트 추가하고 체크 몇 개한 후 Completed 옵션
선택했는데 필터가 적용 안 되는 걸 확인할 수 있음🤨

이건 왜 이러는 걸까❓

보여지는 부분이 App 에서 todoList로 보여지고 있음

todoListState는 이거임 ( 얘로 보여주면 안 됨 )

이젠 filterTodoListState로 보여줘야함❗

filter 한 거에 따라 다른 값들을 보여줘야하는 것

아까와 똑같이 useRecoilValuefilteredTodoListState 가져오면 됨⭕

Completed 옵션 선택하니까
이젠 알맞게 체크된 리스트만 필터링 돼서 화면에 보여줌

다 잘 되는 걸 확인할 수 있음👀


🧮몇 가지 통계 기능 추가하기

Total items는 총 두 개가 있으니까 2이고,
Items completed는 체크된 게 한 개니까 1이고,
Items not completed는 체크 안 된 게 한 개니까 1이고,
Percent completed는 체크된 거 하나 안 된 거 하나니까 50임

🤷‍♀️이 기능을 만들 때 atom으로 만들까 아님 selector를 이용해야 할까❓

selector 사용해야함❗
📌이유 : 어떤 것들에 의존하고 있으므로 selector 사용해야하는 것

현재 todoListState에 의존하고 있음🧱

🔄todoListState가 바뀌면 이것들도 바껴야함

todoList에 통계를 위한 statetodoListStatsState 만들기

▫ src>TodoAtoms.js

🔑key는 관습적으로 이렇게 많이들 함 ( 유니크한 값을 넣어주면 됨 )

get을 이용해서 todoListStateRecoilValue를 가져올거임

✅이건 length로 구하면 됨

filter 이용해서 itemisComplete 된 것만 걸러줌

이건 Total itemsItems completed = Items not completed 이렇게 하면 나옴

totalNum이 0이면 당연히 percentCompleted도 0이 됨
👉 아무것도 완성되지 않았으면 0이 되는 게 맞기 때문

아니면 체크된 리스트 / 리스트의 전체 길이 해주면 됨

🔁return 할 때 어떻게 해줘야할까❓

이럴 땐 객체로 리턴하기

똑같으니까 이렇게 수정

그리고 외부에서 쓸거니까 export로 내보내기🥏

🤓todoListStatesState를 가져와서 사용해야하므로 이걸 위한 컴포넌트도 만들어주기

이 위에서 가져온담에 화면에 보여줄 것

▫ src>components>TodoListStats.js

rafce 해서 함수형 컴포넌트 자동 생성하기

리턴할 때 이걸 리턴하니까

이렇게 해주면 됨

화면에서 보여주기 위해 App.js 안에 TodoListStats 컴포넌트 넣어주기

나머진 잘 됨, 저부분만 수정할 것 ( 퍼센트로 % )

이젠 다 잘 되는 걸 확인할 수 있음🥳


🔮비동기 데이터 쿼리

Selector 이용해서 비동기 요청을 한 데이터를 전역 상태에 넣어주기

selector는 기본적으로 값을 자체적으로 캐싱

만약, 입력된 적 있는 값이라면 그 값을 기억하고🧠
🔄이 값이 다시 호출되면 이전에 캐싱된 결과를
바로 보여주기에 비동기 데이터를 다루는 측면에서 유리함📢

유저 데이터 같은 데이터➡애플리케이션 만들 때
많은 컴포넌트에서 사용되기에 전역 상태로 관리하면 좋음👍

그래서 유저 데이터를 DB 에서 가져올 때
Selector 이용해서 전역 상태에 넣어주겠음🔥
🗣데이터 요청해서 가져온 담에 Selector에다가 넣어줄 것

유저의 데이터를 비동기로 가져올거임

▫ src>UserAtoms.js

👉 atom에 대한 게 많아지면 src 안에 atom 폴더 만들어서 이 안에 파일 만들면 됨

👤1번 유저, export로 내보내기🥏

비동기 요청 보낼 때 fetch 사용했었는데 이보다 많이 사용한게 axios 😎

📥npm install axios로 설치하기

currentUserIdState의 특정 유저에 대한 데이터를 어디서 가져올거냐면❓
👉 jsonplaceholder ( 제 3자 API, User/Post 정보나 더미데이터를 주는 곳 ) ❗

🐱‍👤Recoil 에서 비동기 요청을 selector 에서 보내는 것

get 에서 비동기 요청이니까 async, 저 User에 데이터를 가져올거니까
저게 바뀌면 currentUserNameQuery도 바뀌게 되는 것🔄

export로 내보내주기🥏

▫ src>App.js

UserAtoms.js 안에 있는 currentUserNameQuery 값 가져오기➡useRecoilValue

{userName}만 가져오면 됨✌

🔄새로고침해도 잘 나오는 걸 확인할 수 있음👀

profile
안녕하세요! 퍼블리싱 & 프론트엔드 개발 공부 블로그 입니다!

0개의 댓글