Code.camp/Codecamp

본캠프 33일차

Jayy 2022. 12. 14. 12:16

Optimistic-UI(옵티미스틱 UI)

특정 게시물을 보고 좋아요를 누르게 되면 환경에 따라 좋아요의 수가 올라가는 속도가 다르다.

좋아요를 누르게 되면 백엔드에 likeBoard라는 api에 요청을 보내게 되고, 백엔드는 DB에 요청을 하게 되는데

그럼 DB는 좋아요의 수를 올려두고 올린 좋아요 수를 응답한다. 해당 응답을 백엔드는 다시 브라우저에 응답해주는 것 이다.

그런데 느린환경의 컴퓨터라면, 혹은 백엔드 컴퓨터가 굉장히 먼 곳에 있다면 해당 과정이 굉장히 지연될 수 있다.

이렇게되면 UX가 나빠지기 때문에 옵티미스틱 UI를 사용하게된다.

옵티미스틱 UI란 요청이 서버에 도달하기도 전에 화면의 값을 바꿔버리는 것.

즉, api를 요청하기도 전에 화면에서 바꿔버리고 계속해서 요청을 보내는 것 입니다.

그리고 요청이 성공하고 나면 응답이 돌아올텐데 그때 다시 화면을 업데이트한다. 

만일 중간에 네트워크 문제나 다른 이유로 실패하게 된다면, 이전의 값을 응답으로 보내주고 이전의 값을 화면에 업데이트 한다.

Optimistic-UI 사용해보기

import { useMutation,gql,useQuery } from "@apollo/client"

//좋아요 갯수 가지고 오는 api _ 게시글 조회 api에서 좋아요 갯수만 뽑아 온다. 
const FETCH_BOARD = gql`
	query fetchBoard($boardId: ID!){
		fetchBoard(boardId: $boardId){
			_id
			likeCount
		}
	}
`

//좋아요 카운트 올리는 api
const LIKE_BOARD = gql`
	mutation likeBoard($boardId:ID!){
		likeBoard(boardId:$boardId)
	}
`

export default function(){
	const [likeBoard] = useMutation<Pick<IMutation,"likeBoard">,IMutationLikeBoardArgs>(LIKE_BOARD)
	const { data } = useQuery(FETCH_BOARD,
														{variables :{boardId : "게시글 아이디 넣어주세요!"} })
	
	const onClickLike = ()=>{
		//likeBoard 뮤테이션 함수를 실행하겠습니다.
		void likeBoard({
			variables :{
				boardId : "게시글 아이디 넣어주세요!"
			},

		// 응답을 받고난 후 받아온 응답을 다시 fetch 해줍니다. -> 느리고 효율적이지 못함(백엔드에 요청을 한번더 해야하고 받아올때 까지 기다려야 함)
		//refetchQueries: [
		//	{
		//		query: FETCH_BOARD,
		//		variables : {	boardId : "//게시글 아이디 넣어주세요!" }
		//	}
		// ]

		****//옵티미스틱 UI -> 캐시를 바꾸고 캐시값을 받아오는걸 기다리지 않고 바로 바꿔준다.
		optimisticResponse: {
			likeBoard : (data?.fetchBoard.likeCount || 0)+1
		},
		****// apollo 캐시를 직접 수정을 할 수 있다.(백엔드 캐시가 아니다.) -> 느리지만 효율적임. (백엔드에 요청은 안하지만, 받아올때까지 기다려줘야 한다.)
			update(cache,{data}){
				cache.writeQuery({
					query : FETCH_BOARD,
					variables : {boardId:'게시글 아이디 넣어주세요!'}
					data: {
						// 기존값과 똑같이 받아와야함.
						fetchBoard: {
							_id : '게시글 아이디 넣어주세요!',
							__typename : "Board"
							likeCount: data?.likeBoard
						}
					}
				})
			}
		})
	}

	return(
		<div>
				<h1>옵티미스틱 UI</h1>
				<div>현재카운트(좋아요):{data.fetchBoard.likeCount}</div>
				<button onClick={onClickOptimisticUI}>좋아요 올리기!!</button>
		</div>
	)
}

이렇게 옵티미스틱 UI를 적용하면 컴퓨터 환경에 상관없이 유저 모두가 빠른 서비스를 이용하는 것 같이 속일 수 있다. 

데이터가 중요하지 않고 실패할 확률이 없다면 옵티미스틱 UI를 사용해주시는게 좋다.


스크래핑 vs 크롤링

scraping(스크래핑)

스크래핑을 한국어로 번역하면 ‘긁다’라는 뜻이 되는데, 이 의미처럼 ‘특정 사이트를 스크래핑을 한다’ 라고 하면 특정 사이트의 한 페이지를 쭉 긁어와 1번 가져오는 것을 뜻한다.

crawling(크롤링)

크롤링이란 ‘헤엄치다’ 라는 뜻을 가지고 있으며, ‘크롤링을 한다’ 라고 하면 특정 사이트에서 돌아다니며 버튼을 클릭해 여러 페이지를가지고 오는 것을 뜻한다.

즉, 여러번의 스크래핑을 한 것이 크롤링이라고 생각하면 된다.

크롤링시 주의점

  1. 크롤링 해온 데이터를 상업목적으로 사용시 소송대상이 될 수 있다.
  2. 너무 많은 접속으로 해당 회사 서버에 부하를 주게 될 경우, 공격으로 판단되기 때문에 주의해야 한다.

HTTP 응답 결과

주소창에 입력된 페이지에 대한 요청은 프론트엔드 서버에서 처리하게 되고 프론트서버에서는 요청에 대한 응답 결과물로 html을 반환하게 되고, 해당 결과물이 우리가 Network에서 보는 html이다.

주소창에 입력된 페이지에서 다른 api요청을 보낼때는 백엔드 서버에서 처리하게 된다.

백엔드 서버에서는 다양한 응답 결과물을 반환할 수 있는데, 응답 결과물로 html,json,xml을 반환할 수 있다.

즉, 브라우저의 주소창 또한 http요청의 도구였다는 것을 알 수 있다.

백엔드에서 받아온 결과값들을 브라우저가 해석해 화면에 그려주는 것.

백엔드의 응답결과 → 우리는 지금까지 백엔드의 결과물로 JSON이 날아온다고 알고있다. 하지만 백엔드의 응답 결과물로 무조건 JSON이 날아오는 것은 아니며 JSON 이외에도 소스코드가 날아올 수 있다.


서버사이드 렌더링이 필요한 이유

1. OG태그에서의 서버사이드 렌더링

head태그를 하드코딩으로 만들어주면 어디서든 OG태그를 볼 수 있다.

하지만 OG태그를 언제나 하드코딩을 할 수 있는것은 아니다.

import Head from 'next/head'

const FETCH_DATA = gql`
	//상품 상세를 가지고 오는 쿼리문
**`**

export default OpengraphHeadPage(){

const {data} = useQuery(FETCH_DATA)
	
	return(
		<div>
			<Head>
				<meta property="og:title" **content=`${data.fetchBoard.contents}`**/>
				<meta property="og:description" content="환영합니다."/>
			</Head>
				<h1> 오픈 그래프 연습입니다~ </h1>
		</div>
	)
}

이런식으로 data를 가지고 오고 가지고 온 data를 og 태그에 넣어 주었다고 가정한다면 ,초기 렌더링을 했을때는 백엔드 요청을 하지 않기 때문에 메타 태그가 비어있다.

이후에 useQuery가 실행되고난 이후에야 meta 태그에 들어간 data.fetchBoard~ 이부분이 채워지게 되며 그제서야 데이터가 들어오게 된다.

즉, 브라우저에서 요청한 결과와 서버에서 보여지는 결과(postman요청결과)가 다르다는 뜻.

이런 경우를 대비해서 서버사이드 렌더링이 필요하다. 특정 주소에 서버사이드 렌더링 주소로 설정할 수 있다.

따라서 만일 서버사이드 렌더링 주소일 경우 프론트 서버에 요청을 하면 바로 응답을 보내는 것이 아닌 백엔드로 요청을 보내 데이터를 모두 꺼내와 합친 후 최종결과를 응답으로 전달해준다.

동적 페이지에 OG를 적용해주시고 싶으시다면 서버사이드 렌더링을 적용해주어야 한다.

서버사이드 렌더링 OG태그 만들어보기

서버사이드 렌더링을 적용한 OG태그를 만들기 위해서는 useQuery를 사용하는 것이 아니다.

useQuery를 사용하는 대신 getServerSideProps를 사용할 것임.

export default function OpengraphProviderPage(props: any) {
  console.log("========");
  console.log(props);
  console.log("========");
  
  return (
    <>
        
        
 
    
  );
}

// 1. getServerSideProps는 존재하는 단어이므로 변경이 불가능하다.
// 2. getServerSideProps는 프론트엔드 서버에서만 실행된다.(Webpack 프론트엔드 서버프로그램)
export const getServerSideProps = async () => {
  console.log("여기는 서버입니다!");

  // 1. 여기서 API 요청 - 아폴로 세딩이 되어있지 않아 grqphql-request를 이용해야 한다.
  const graphQLClient = new GraphQLClient(
    "<https://backend10.codebootcamp.co.kr/graphql>"
  );
  const result = await graphQLClient.request(FETCH_USEDITEM, {
    useditemId: "634f50f06cf469002995d5c9",
  });
  console.log(result);

  // 2. 받은 결과를 return
  return {
    props: {
      qqq: { 
        name: result.fetchUseditem.name,
        remarks: result.fetchUseditem.remarks,
        images: result.fetchUseditem.images,
      },
    },
  };
};

이런식으로 getServerSideProps를 사용하게 되면 실행하게 되면 서버에서 실행된다.

그럼 서버에서 실행 후 결과물을 리턴해주고 리턴된 props는 페이지 안으로 들어가게 되고 해당페이지는 결과값을 이미 다 받았기 때문에 데이터가 모두 있는 상태에서 화면에 그려지게 된다.

즉, 이미 데이터를 모두 채운채 브라우저로 보내주게 되는 것.

getServerSideProps는 처음 접속되었을 때 실행되는 부분이기 때문에 apolloSetting이 되어있지 않다. 따라서 우리가 refreshToken에서 했던 방식과 동일하게 graphql-request 를 사용해 api를 요청해야 한다.

⚠️ pageProps란? → getServerSideProps를 실행 후 반환받는 값이 props 이었다. 해당 props는 페이지의 props로 쏙 들어가게 되는데, 이런 props를 pageProps라고 한다.

즉, 서버사이드렌더링 완료 후 리턴되어 페이지의 props로 들어가는 props를 pageProps라고 한다.

이전에는 데이터가 비어있는 상태에서 브라우저에서 useQuery를 실행해서 데이터를 채워넣었는데, getServerSideProps를 사용하면서 데이터를 채운 완벽한 상태에서 브라우저로 보내줄 수 있게되었다.

 

⭐️ 2. SEO(Search Engine Optimization)_검색 엔진 최적화 ⭐️

사실 서버사이드 렌더링이 필요한 이유를 검색하면 **검색 엔진 최적화(SEO)**가 가장 많이 언급 된다.

검색엔진 이라고 함은 네이버, 구글, 다음등을 말하며 해당 사이트들은 자체적인 검색봇이 있다.

각각의 검색봇은 24간동안 여러 사이트를 돌아다니며 해당 사이트가 어떤 사이트인지 파악하는데, 서버사이드 렌더링 처리가 되지 않은 사이트는 초기 렌더링 시 데이터가 모두 비어 있게 되어 검색봇은 페이지가 무슨페이지인지 모르는 상황이 생긴다.

하지만 서버사이드 렌더링을 하게되면 html,css,js 받아올 때 이미 데이터를 모두 완벽히 받아와 보여주기 때문에 검색봇이 해당 사이트가 무슨 사이트인지 알 수 있다.

 

'Code.camp > Codecamp' 카테고리의 다른 글

본캠프 35일차  (0) 2022.12.19
본캠프 34일차  (0) 2022.12.15
본캠프 32일차  (0) 2022.12.13
본캠프 31일차  (0) 2022.12.12
본캠프 30일차  (0) 2022.12.09