25일차 - Destructuring, Custom Hooks

류연찬·2023년 5월 7일
0

Codecamp FE07

목록 보기
25/39

Destructuring(비구조화 할당/구조 분해 할당)

객체의 구조 분해 할당

const child = {
  name: '철수',
  age: 21,
  school: '코딩학교'
}

위와 같은 객체에서 name, age, school 이라는 변수를 만들고 싶다고 합시다.

그럼 우리는

const name = child.name

const age = child.age

const school = child.school

이런식으로 하나씩 생성해주었습니다

그런데 만일, 변수가 3개가 아닌 7개를 만들어야 했다면 혹은 그 이상 만들어야 했다면 너무 힘들 것 같지 않나요?

이런 수고로움을 덜어주는 것이 비구조화 할당 입니다.

즉, 비구조화할당이란 변수를 한번에 모두 선언하고 할당 할 수 있도록 도와주는 것 입니다.

위의 세줄을 비구조화 할등을 이용하면 아래의 한 줄로 줄어들게 됩니다.

// 객체의 비구조화 할당
const { name, age, school } = child

객체의 구조분해 할당은 선언부에 {중괄호}를 사용하며, 객체의 key값을 변수명으로 사용합니다.

또한 할당부에는 객체의 이름을 넣어주시면 됩니다.

useQuery와 구조 분해 할당

const { data, loading } = useQuery(FETCH_BOARDS)

우리가 당연한듯 사용했던 위의 코드가 사실 구조 분해 할당이었다는 것이 너무 신기하지 않나요?

useQuery의 실행후 return값이 객체 이므로 객체의 구조분해 할당 입니다.

저렇게 습관처럼 받아왔던 데이터들을 사실은 const aaa = useQuery(FETCH_BOARDS) 로 받아와 aaa.data, aaa.loading 이렇게 사용할 수 있었던 것 입니다.

하지만 이렇게 사용하는 것 이 비효율적이라 구조분해 할당을 사용해 조금 더 편리하게 사용한 것 뿐 입니다.

배열의 구조 분해 할당

const classmates = ['철수', '영희', '훈이']

우리는 이전까지 배열의 원소를 각각 child1, child2, child3에 할당 하려면

const child1 = classmates[0]

const child2 = classmates[1]

const child3 = classmates[2]

이런식으로 하나씩 선언하고 할당을 해왔습니다.

하지만 위에서 객체의 구조분해 할당을 배운 것 처럼 배열의 구조분해 할당 역시 배워 조금 더 편리하게 선언과 할당을 해보도록 하겠습니다.

//베열의 구조분해 할당
const [child1, child2, child3] = classmates

배열의 구조분해 할당은 선언부에 [대괄호]를 사용하며, 객체의 비구조화할당과 다르게 변수명은 마음대로 주셔도 무방합니다.

그리고 할당부에는 배열의 이름을 넣습니다.

배열의 원소 할당은 인덱스의 순서대로 들어갑니다.

Rest 파라미터

우리가 특정 객체에서 지우고싶은 데이터가 있을 때 어떻게 할까요?

과연 delete사용해 delete child.moneydelete child.hobby 를 할까요?

사실 원본을 건들이는 일은 그리 바람직하지 못합니다.

원본이 어디서 어떻게 사용되고 있을 지 모르기 때문에 원본을 사용하는 곳에서 예상치 못한 에러를 직면하게 될 수 있습니다.

따라서 원본을 건들이지 않고 삭제하기 위해 rest 파라미터를 이용합니다.

rest 파라미터는 구조분해 할당과 함께 사용합니다.

const { money, hobby, ...rest } = child

이렇게 적으면 rest부분에는 money와 hobby를 제외한 모든게 들어가게 됩니다.

Custom Hooks

지금까지 우리는 useState , useContext , useEffect , useRef 등 다양한 react 내장 Hook 을 사용해 왔는데,사실 Hook의 정체는 함수였습니다.

따라서 사용시에 함수를 호출 하는 것 처럼 사용을 하는 것 이었습니다.

Custom Hook 이란 이름 그대로 개발자가 스스로 커스텀 한 훅을 의미하게 됩니다.

Custom Hooks 사용시 주의 사항

그런데 Hook이 함수라면, custom hook역시 함수일텐데 일반함수와는 어떤 차이점이 있으며 비슷하면 그냥 함수를 쓰면 되지 굳이 왜 사용하는 것 일까요?

사실 별 차이는 없지만, 내부에서 useState와 같은 hook을 사용하게 되면 customhook이라고 합니다.

💡 customhook을 사용하게되면 함수 네이밍에 use 를 사용해주셔야 합니다.

📖 use 는 필수로 붙여야하나요?
붙이지 않았을 경우 실행은 되지만 의도치 않은 에러를 맞이할 수 있습니다. 그러면 에러 핸들링이 굉장히 어려워 질 수 있음으로 use 를 붙여주는게 중요합니다.
https://ko.reactjs.org/docs/hooks-custom.html


Custom Hooks 만들기

import { useState } from react

// 커스텀 훅 함수 
export const useFetch = (url) => {
  const [data, setData] = useState([])

  useEffect(() => {
    fetch(url)
      .then(res => res.json())
      .then(resJson => setData(resJson))
  }, [url])

  // 커스텀 훅의 return부분 입니다.
  return data
}

custom hook은 컴포넌트가 아닌 함수이기때문에 return 부분이 JSX가 아닙니다.

이부분을 이해하시면 custom hook을 더 이해하기 쉬울 수 있습니다.

refetch의 문제점과 개선 방법(writeQuery, readQuery)

지금까지 우리는 등록/삭제 이후 refetch를 통해 목록을 업데이트 해왔습니다.

하지만 이제부터는 refetch 를 하지 않고 apollo-cache-state를 직접 업데이트하는 방법을 사용해 볼 것 입니다.

cache를 직접 업데이트하는 방법을 배워보기 이전에 선수되어야하는 부분이 있어 간략히 짚고 넘어가보도록하겠습니다.

파라미터와 구조 분해 할당

const onClickAAA = ({name, age, school}) => {
  console.log(name)
}

const child = {
  name: '철수',
  age: 13,
  school: '코딩초등학교'
}

onClickAAA(child)

update cache-state

//apollo-cache-state 파일

//등록하기 로직
const onClickSubmit = async () => {
	await createBoard({
      variables: {
        createBoardInput: {
        	//writer,contents 등등 보내줄 내용들
      },
    },

    update(cache, { data }) {
      // createBoard하고 돌려받은 리턴값을 의미합니다.(지금 등록한 글) -> gql부분을 보면 알 수 있겠죠?
      data.createBoard
      //캐시를 직접 수정합니다.
      cache.modify({
        fields: {
          fetchBoards: (prev) => {
            return [data.createBoard, ...prev]
          }
        }
      })
    })
}

prev 에는 현재의 fetchBoard 의 상태, 즉 10개의 배열이 들어갑니다.

그리고 return 값으로 fetchBoard 가 업데이트되게 됩니다.

우리는 등록 이후에 목록을 업데이트해주는 것 이기때문에 prev의 목록이전에 데이터를 추가해 return 해주시면 됩니다.

이렇게 하시면 globalState에 있는 cache-state 데이터가 바뀌게 됩니다.

등록은 앞에 데이터를 추가해주면 되었습니다. 그럼, 삭제는 어떻게 했을까요?

삭제는 간단히 filter를 이용해 원하시는 Board의 id를 매치 시켜 삭제 해주시면 됩니다.

아래에서 코드를 보며 같이 알아보도록 하겠습니다.

const onClickDelete = async () => {
  	await deleteBoard({
      variables: {boardId},
      update(cache, {data}) {
        // 삭제할 Board의 id
        const deleteId = data.deleteBoard
        cache.modify({
          fields: {
            // _id를 가지고 오고싶다면 readField를 사용하셔야 합니다
            fetchBoards: (prev, {readField}) => {
              // deleteId가 아닌 Board의 Id만 걸러서 가지고 옵니다 (9개)
              const filteredPrev = prev.filter(el => readField(el._id) !== deleteId) {
                return [...filteredPrev]
              }
            }
          }
        })
      }
    })
}

💡 apollo-cache-state란?
우리는 어떤 data를 가지고 왔을 때 컴포넌트에 저장했던 것이 아닌 globalState에 저장했ㅅ브니다. app.js에서 설정해주었던 client의 cache가 사실은 apollo client인 것 입니다.

보통 cache 업데이트 방법은 무한스크롤을 사용하는 페이지에서 많이 사용하는 데이터 최신화 방식입니다.

하지만 방식에 있어서 어떤것이 정답이다! 라는 것은 없으며, 상황에 따라 가장 효율 적인것을 선택해서 사용하시는 것이 중요합니다.

타입스크립트 any vs unknown

Generic, 유틸리티 타입 등을 배우기에 앞서 특이한 속성을 가진 두 가지 타입에 대해 먼저 배워봅시다.

any

’어떠한 것이든지, 누구든지’ 라는 뜻으로, 어떠한 타입이 입력되더라도 전부 허용하는 타입입니다. 요소에 any 타입을 부여할 경우 사실상 타입스크립트가 아닌 자바스크립트를 사용하는 것이나 마찬가지가 됩니다.


unknown

’알 수 없다, 모른다’ 라는 뜻으로, 개발자에게 주의를 주는 용도의 타입입니다. 타입이 지정되지 않았으므로 연산에 오류가 발생할 수 있음을 경고합니다.

필요에 의해 TypeScript 3.0에서 도입된 타입입니다.

0개의 댓글