7일차 - React State, refetchQueries

류연찬·2022년 11월 13일
0

Codecamp FE07

목록 보기
7/39

State

state라는 react 컴포넌트에서 데이터를 담기 위한 상자입니다.
기존 자바스크립트에서는 변수로 데이터를 저장하고 사용했지만 컴포넌트에서는 state를 사용합니다.

// let으로 count 예제 실험해보기
function New() {
    let count = 0     // let으로 변수 만들기(초기값: 0)
    
    function handleClick() {
        count = count + 1     // 갯수는 증가했지만, 화면에는 반영이 안됨
    }

    return (
        <div>
            <h1>{count}</h1>
            <button onClick={handleClick}>let을 사용하여 count 증가</button>
        </div>
    )
}

export default New
// state로 count 예제 실험해보기
import { useState } from 'react'

function New() {
    const [count, setCount] = useState(0)     // state로 변수 만들기(초기값: 0)
    
    function handleClick() {
        setCount(count + 1)     // 갯수가 증가하면서, 화면에 정상적으로 반영됨
    }

    return (
        <div>
            <h1>{count}</h1>
            <button onClick={handleClick}>state를 사용하여 count 증가</button>
        </div>
    )
}

export default New

🔔 { state, setState, useState } 언제 사용하나요?

  • 회원가입, 게시물 작성 내용 등을 서버 컴퓨터에 전송하기위해 변수에 담아둘 때 사용합니다.
  • 작성한 내용을 검증하고 잘못된 부분을 빨간색으로 표기할 때 사용합니다.

setState 원리

input에 값이 들어있으면 버튼 색을 바로 변경하는 예를 들었을 때, input에 하나만 입력하면 버튼 색이 변하지 않는 것을 볼 수 있습니다.
2개를 쳐야 반영이 되는 것이 확인할 수 있는데 이러한 이유는 re-rendering 때문입니다.

setState를 통해 값이 변경이되면 바뀌는 값은 임시 저장소에 들어가게 되고 모든 처리가 끝나면 re-rendering이 되면서 임시 저장소에 있는 값들을 꺼내 화면에 출력하게 됩니다.

즉각으로 처리되고 싶다면 임의의 변수보다 event.target.value를 사용하면 됩니다.

const [writer, setWriter] = useState("")

// input value를 받아오는 함수
const onChangeWriter = (event) => {
  setWriter(event.target.value)
}

// input과 state에 입력되는 순서
// input : ㄱ, 가, 기ㄴ, ...
// state : "", "ㄱ", "가", ...
const classmates = ["철수", "영희", "훈이"]

// (1) mapping을 이용해서 배열 생성
const aaa = classmates.map(el => <div>{el}</div>)
return (<div>{aaa}</div>)

// (2) 배열 선언
const aaa = [<div>철수</div>, <div>영희</div>, <div>훈이</div>]
return <div>{aaa}</div>

// (1)과 (2) 출력은 동일

// 출력값
<div>
  <div>철수</div>
  <div>영희</div>
  <div>훈이</div>
</div>

refetchQueries

refetchQueries는 기존에 받아왔던 데이터가 변경되었을 경우 최신 데이터로 다시 fetch 해주기 위해 사용됩니다.

// 삭제 mutation
const deleteBoard = async () => {
  try {
    const result = await deleteBoard({
      variables: {
        boardId: router.query.boardId
      },
    });
  } catch(error) {
    console.log(error);
  }
}

위의 코드는 삭제 Mutation입니다.
위 코드는 삭제 Mutation이 실행 된 후에는 데이터가 변경되었을테지만 아직 최신 데이터가 반영 되지 않습니다.
따라서 refetchQueries를 이용해 최신 데이터로 다시 받아오겠습니다.

// refetchQueries를 이용해 최신 데이터 받아오기
const deleteBoard = async () => {
  try {
    const result = await deleteboard({
      variables: {
        boardId: router.query.boardId
      },
      // refetchQueries로 데이터 다시 받아오기
      refetchQueries: [
        {
          query: FETCH_BOARDS
        },
      ]
    });
  } catch(error) {
    console.log(error);
  }
}

useMutation 함수 안에서 refetchQueries라는 키가 있다는 것을 알 수 있습니다. refetchQueries는 Apollo에서 제공하는 기본 기능입니다.

refetchQueries는 배열로 시작하여, 그 안에 어떤 query를 하고, 그 query의 variables가 무엇인지 다시 설정해주면 Mutation이 성공적으로 끝났을 경우 refetchQueries를 실행시켜줍니다.

map의 index를 key로 사용 시 발생하는 문제점

React 공식 문서에 나오는 List와 Key

간단한 예제를 보겠습니다.

import { Test } from '../../src/test2';

export default function Test2() {
	const List = ['사과', '딸기', '바나나'];

	return (
		<>
			{List.map((data) => (
				<Test>{data}</Test>
			))}
		</>
	);
}

위의 예시처럼 map을 사용할 때, key값을 부여하지 않았을 경우 오류가 발생합니다.
그 이유는 아래와 같습니다.

React에서 Key가 필요한 이유

해당 경고는 React가 어떤 요소를 변경, 추가, 삭제할지 식별하기 위함입니다.
key가 없는 경우에는 가상 DOM을 비교하는 과정에서 순차적으로 비교하여 변화를 감지합니다.
key가 있다면, 이 값을 사용하여 어떤 것이 수정이 됐는지 빠르게 감지할 수 있습니다.

위의 설명을 짧게 보충한다면, React에서는 기존데이터와 바뀐 데이터를 비교하여 바뀐 부분을 화면에 그려줍니다.
여기서 비교할 때, 고유한 key값이 없다면 모든 데이터를 비교해야하지만, key가 있으면 key값만 비교하여 key가 추가됐는지, 삭제됐는지만 비교하여 불필요한 비교나 렌더링을 없애줍니다.

그러기 위해서 key는 안정적인 고유성을 부여하기 위해 중복되는 값이 아닌 것으로 지정해줘야 합니다.
(만약 key를 지정하지 않을 경우 자동으로 index를 키로 사용합니다. 하지만 이는 좋은 방법이 아니라 경고가 뜹니다.)

그래서 React 공식 문서에서도 key값으로 id를 주는 것을 추천합니다.

// 고유한 key값 선언
// 예제이기 때문에 id가 없지만 예시로 넣어두었습니다
import { Test } from '../../src/test2';

export default function Test2() {
	const List = ['사과', '딸기', '바나나'];

	return (
		<>
			{List.map((data) => (
				<Test key={id}>{data}</Test> // 고유한 key(id)값
			))}
		</>
	);
}

Index를 Key로 줘도 괜찮은 상황

  • 정적인 데이터. 계산되지 않고 변경되지 않는 데이터
  • map에 있는 모든 데이터에 id가 없을 경우
  • 데이터가 재정렬되거나 필터링 되지 않는 경우. (계속 그 자리 그대로)

0개의 댓글