[코드캠프]21,22일차_TIL_Recoil

윤성해·2023년 4월 12일
0

프론트엔드_TIL

목록 보기
20/27
post-thumbnail

수업 목차

  1. 컴포넌트와 props, data, prev,el,graphql-variables의 실체
  2. rest-api의 문제점과 엔드포인트
  3. graphql, rest-api와의 관계
  4. 글로벌 스테이트
  5. Recoil

리뷰

검색기능 만들어서 컴포넌트로 분리해주었다.
언제든 import 할 수 있는 장점이 있음

// searchBar.container 파일 
import SearchBarUI from '파일 경로'

const SearchBar = (props)=>{

	// 0.2초 안에 별다른 일이 없으면 요청을 해줍니다.
	// data는 아래의 event.target.value로 들어오게 됩니다.
	const getDebounce = _.debounce((data)=>{
			// 디바운싱이 이뤄진 이후엔 검색 키워드로 refetch가 이뤄져야 합니다.
				props.refetch({ search: data, page: 1 })
			// 검색 결과 갯수에 따라서 페이지네이션이 바뀌기 때문에 함수로 만들어 내려줍니다.
				props.refetchBoardsCount({ search: data })
			// 검색 결과와 일치하는 키워드에 색깔 입혀주는 함수 
				props.onChangeKeyword(data)
		},200)
	const onChangeSearchbar = (event)=>{ getDebounce(event.target.value) }

	return <SearchBarUI onChangeSearchbar={onChangeSearchbar}/>
	}

위에서 보이는 props는 Board 리스트 페이지에서 내려주는 것들 임!

// searchBar.presenter 파일 
const SerchBarUI = (props)=>{

	return(
			<SearchBarWrapper>
				<SearchBarInput
					placeholder = "검색어를 입력해주세요."
					onChange = {props.onChangeSearchbar}
				/>
			</SearchBarWrapper>

		)
	}

1. props의 실체

우리가 그동안 알고있었던 함수형 컴포넌트는 함수이기 때문에 <Presenter count={123}/>{Presenter({count:123})}과 같이 사용할 수 있습니다.

즉 Presenter함수를 해당 위치에서 실행시키겠다는 뜻 입니다.

Presenter함수의 인자(argument)를 한번 보겠습니다. count가 함수의 인자 부분에 들어가 있네요!
그리고 aaa로 넘겨준 인자를 받고있습니다. 그런데, aaa는 props의 자리였단걸 기억 하시나요?
따라서, props는 사실 함수의 파라미터였습니다.

💡tip
함수와 컴포넌트의 차이점
→ 컴포넌트는 return 값으로 JSX가 반환되어야 합니다.

2. el 의 실체

map의 el의 실체를 알아보기 전에, 우선 기본적인 것 먼저 알고 넘어가도록 하겠습니다.

//함수의 선언
const getProfile = (aaa,bbb)=>(
		console.log(`${aaa}${bbb}입니다.`)
	)
//함수의 실행
getPrfile("훈이",2)

// <----실행 결과----->
// 훈이는 2입니다.

aaa 부분에는 “훈이”가 들어오고, bbb에는 2가 들어와 결과적으로 “훈이는 2입니다.” 가 나오게 됩니다.
즉, 인자로 넘겨주는게 여러개 일 경우 파라미터도 인자의 갯수만큼 늘어나며, 넘겨준 순서대로 들어오게 됩니다.

그럼 map을 한번 봅시다.

["철수","영희","훈이"].map((el,index)=>(console.log(`${el}${index}번째 입니다.`)))

위의 코드를 잠시 생각해보면 위의 map을 (”철수”,0) (”영희”,1) (”훈이”,2) 이렇게 실행시켜주는 것 입니다.
위에서 잠시 본 내용처럼 여러개의 인자를 순서대로 넘겨주는 것인데, map에서 넘겨주는 인자의 순서는 배열의 value값→해당 value의 insdex 값 순서로 들어가게 됩니다. 또, 파라미터의 네이밍은 뭐가 들어가도 상관없습니다.

그렇다면, 아래에서 index는 무엇을 의미할까요?

이름만 index일 뿐이지, 배열의 각각의 원소인 "철수", "영희", "훈이"를 의미합니다
즉 map 또한 함수였으며, el과 index는 함수의 파라미터입니다.

3. prev의 실체

그렇다면, state의 prev도 마찬가지겠죠?

setCount(prev => prev+1)

prev 역시, 함수의 파라미터였습니다.

setCount((prev)=>{return prev+1})

위의 setCount 함수의 인자로 화살표 함수가 들어가고, 화살표 함수 안의 prev는 함수의 파라미터가 되겠습니다.

4. graphql-variables의 실체

const CREATE_BOARD = gql`
mutation createBoard($writer: String){
		createBoard(writer: $writer){
			_id
		}
	}
`

위의 $가 붙은 것 들은 변해도 괜찮은 변수라서 $writer가 아닌 $hello가 되어도 괜찮습니다.

💡 쿼리를 날릴 때 두 번 적어주는 이유
→ 한 요청에서 여러가지의 api요청을 날릴 수 있기 때문입니다.

const REQUEST = gql`
mutation 한번에요청할그룹이름 ($변수 : String){
	원하는API1(백엔드지정:$변수){
		//받아올 것
	}

	원하는API2(백엔드지정:$변수){
		//받아올 것
	}
}
`

위와 같이 REQUEST 한번에 여러가지 API를 묶어서 한번에 요청할수 있도록 되어있기때문에 겉에 적어주는 부분은 그룹화를 위한 부분이다라고보시면 되고, 백엔드에 보내지는 부분은 내부에 적힌 api들을 보내게 됩니다.

쉽게 말해 한번의 mutaion에 createProduct와 createBoard를 보낼 수 있다는 말 입니다.

5. rest-api의 문제점과 endpoint

endpoint란?
→ API가 서버에서 리소스에 접근할 수 있도록 가능하게 하는 URL 입니다.

graphql이 없던 시절 즉, rest-api를 사용하던 시점의 가장 큰 문제점은 너무 많은 endpoint가 만들어진다는 점 이었습니다. rest-api 에서는 post, get, put, delete, update 방식만해도 이미 endpoint가 5개가 생성되기 때문에 이외의 endpoint를 추가하게 되면 상당히 많은양의 endpoint가 생기게 됩니다.

언더페칭과 오버페칭

  1. 오버페칭
    graphql은 api 요청이후 결과값으로 필요한것만 받아오는 반면, rest-api는 결과값을 모두 받아오게 됩니다. 필요없는것까지 모두 받아오는 과정을 오버페칭이라고 부릅니다.
  2. 언더페칭
    rest-api는 endpoint에 body를 넣어 보내기 때문에 하나의 endpoint에 하나의 body만 들어가게 됩니다.
    따라서 한번에 여러개의 api를 요청할 수 있는 graphql과는 다르게 rest-api는 한번에 하나의 api만을 요청할 수 있습니다.
    내가 필요한건 3개의 api인데 한개씩 여러번 받아오는 것을 언더 페칭이라고 합니다.

6. graphql과 rest-api의 관계

rest-api 의 위와 같은 문제점을 개선하기 위해 나온 것이 바로 graphql입니다.
graphql은 rest-api의 post 방식에서 data를 넣을 수 있음을 이용해 만들어낸 방식 입니다.
즉, 완전히 새로운 방식이 아닌 rest-api의 post방식의 응용이라고 볼 수 있습니다.

graphql은 post방식의 body에 내가 실행시킬 함수의 이름을 적어서 endpoint를 요청합니다.
그렇게 되면 해당 이미 만들어진 함수들 중 매칭 된 함수가 실행되고, 원하는 결과값을 받아 올 수 있게 됩니다. 이렇게 graphql은 endpoint문제와 언더페칭과 오버페칭문제를 모두 해결했습니다.

추가 참고 자료!!
1. 언더패칭,오버페칭
레스트api 에서 배너, 사이드바, 내용 등등 3개의 데이터를 받아와야 한다고 가정할 때

묶음요청이 되지 않았다. 세번 요청해야함. 그래프큐엘은 한방에 묶어서 한번에 요청할 수 있다. -> 레스트api의 언더페칭 문제점 그래프큐엘이 해결
또 언더페칭말고 오버페칭 문제점도 있다. 쓸데없이 오버해서 많이받아온다.
리스트 부분에서 제목 , 작성자, 날짜만 요청할 수 없고 그냥 모든 데이터 다받아야했었음

REST-API는 이렇게 요청했었지유

그래프큐엘도 사실은 resp-api이다.!!
로직상 실패가 뜨더라도, 성공인지 실패인지 애매해서 일단은 성공으로 뜬다.(200) ex)왼쪽 페치보드는 성공 페치프로덕트는 실패라고 보았을때

저기 쿼리는 우리가 생각하는 무테이션 쿼리가 아니고 그냥 키네임 자체가 쿼리이다.

주소가 /그래프큐엘 하나여서 캐시가 어렵다.
그래프큐엘을 rest-api 에서 사용해보자

  • 포스트 바이부분에 raw데이터 추가
  • key 는 무조건 query

7. 글로벌 스테이트(global state)

사이트를 만들다 보면 하나의 state가 여러 페이지에서 필요한 경우가 있습니다.
예를들면 isLogined 같은 state는 게시글 목록이나 결제 컴포넌트 같이 여러가지 컴포넌트에서 사용됩니다.
그럼 매번 props로 내려줄까요? 이럴 때 사용하는것이 글로벌 스테이트 입니다.

store에 state를 저장해두고 필요한 컴포넌트에서 import해서 사용하기때문에 props drilling을 하지 않아도 되고 편리합니다.
이런 전역상태관리(global state) 툴로는 context-Api, Redux, Recoil등이 있습니다.
Redux는 너무 어렵고 비효율 적이기 때문에 context-api의 원리와 recoil을 보도록 하겠습니다.
Redux -> MobX -> SWR ( react-query, apollo-client )

fetchPolicy

recoil과 context-api를 보기전에 , apollo-client의 고급 기능을 먼저 보도록 하겠습니다.
여러 컴포넌트가 있고, 여러 컴포넌트들이 공유할 수 있는 global state가 있다고 해보겠습니다.
apollo-client로 global state를 만들게되면 Apollo-Cache 라는곳에 저장되게 됩니다.
만일 2번 컴포넌트에서 useQuery를 해오게 되면 useQuery를 해서 받아온 데이터가 Apollo-Cache에 저장된 후 컴포넌트로 들어오게 됩니다.

이후에 3번 컴포넌트에서 같은 데이터를 요청하게 되면, Apollo-Cache 에 먼저가서 데이터가 있는지 확인하고 없으면 백엔드에 요청을 있으면 백엔드에 요청을 하지 않고 컴포넌트로 바로 보내주게 됩니다. 이를 Apollo-client의 fetchPolicy(fetch 정책)라고 합니다.

fetchPolicy에는 여러가지 기능들이 있으며, 변경이 가능합니다.
fetchPolicy의 기능

  • cache-first default → 캐시에 있는지 먼저 확인
  • network-only → 캐시에 있든 없든 무조건 백엔드에 요청

usequery 쓰면 이미 캐시에 저장이 된다. 서버데이터 캐싱(react-query, apollo-client)

Redux 에서도 쉽게 Redux-toolkit을 만들었다. Redux-Toolkit-Query(RTK query)
1. RTK query, apollo-client, react-query 세개중 하나 골라서 쓰는게 요새 트렌드이다.
2. 아폴로클라이언트랑 리액트 쿼리는 많이 비슷하다. 우리는 아폴로클라이언트, 리콜 사용

Recoil

프론트에서 자체적으로 생성되는 데이터는 어디다 넣어두냐! 라고 했을때 몇가지 방안들이 나왔지만 우리는 그중에 recoil 이라는 라이브러리를 사용해보도록 할 것 입니다.

프론트에서 관리하는 데이터라고 해봤자 많은 부분을 차지하지 않을 텐데 리덕스를 사용하기에는 너무 헤비하기 때문에 recoil을 사용할 것 입니다.

설치
1. npm 사용자 : 터미널에 npm install recoil 을 입력
2. yarn 사용자 : 터미널에 yarn add recoil 을 입력

세팅

//app.tsx 파일 
import {
  RecoilRoot,
  atom,
  selector,
  useRecoilState,
  useRecoilValue,
} from 'recoil';

function App() {
  return (
    <RecoilRoot>
		//RecoilRoot로 모든 컴포넌트를 묶어주세요
      <Component />
    </RecoilRoot>
  );
}

사용
Recoil에서는 Atom으로 state의 일부를 보여줍니다.
그리고 컴포넌트들은 자신이 필요한 Atom을 참조하고 있습니다. 따라서 자신이 참조하고 있는 Atom에 변화가 있으면,해당 atom을 참조하는 모든 컴포넌트에서 리렌더링이 일어납니다.

// Atom
const textState = atom({
  key: 'textState', // state의 이름
  default: '', //초기값
});

위의 아톰을 사용하기 위해서는 useRecoilState를 사용해야합니다.

// TextInput 컴포넌트 
function TextInput() {
  const [text, setText] = useRecoilState(textState);

  const onChange = (event) => {
    setText(event.target.value);
  };

  return (
    <div>
      <input type="text" value={text} onChange={onChange} />
      <br />
      Echo: {text}
    </div>
  );
}

위와같이 사용하게 되면, textState를 참조하고 있는 모든 컴포넌트에서 재렌더가 일어나게 됩니다.

  • useState() 안에 초깃값 설정은 따로 빼놓은 store 폴더 안에서 해주고 useRecoilState를 불러오기!

Recoil 공부하기

profile
Slow and steady wins the race.

0개의 댓글