들어가기
예를 들어, 손흥민 팔로우를 loading한다고 할때, data가 너무 많으면,
loading시 error가 날수도 있고, server가 힘들진다.
따라서, 스크롤이 화면 아래에 왔을때, 이어서 3~4개의 data를 loading하게
하는것, 여기서 feed부분만 설정해 본다

1. server쪽 부분.

1-1. seeFeed/seeFeed.typeDefs.js

import { gql } from 'apollo-server'

export default gql`
  type Query {
    seeFeed(offset: Int!): [Photo]
  }
`

variables에 offset을 변수로 받도록 설정한다.

1-2. seeFeed/seeFeed.resolvers.js

import prisma from '../../client'
import { protectedResolver } from '../../users/users.util'

export default {
  Query: {
    seeFeed: protectedResolver((_, { offset }, { loggedInUser }) =>
    ///1.offset을 variables로 받도록 설정함
    
      prisma.photo.findMany({
        take: 2,
        skip: offset,
        ///take: 2는 맨 처음에 2개의 data를 불러온다는 뜻.
        ///skip: offset 은 이후는 offset의 값에 따라 data를 불러 오겠다는 의미
        ///나머지 부분은 front 에서 설정함.
        
        where: {
          OR: [
            {
              user: {
                followers: { some: { id: loggedInUser.id } },
              },
            },
            { userId: loggedInUser.id },
          ],
        },
        orderBy: { createdAt: 'desc' },
      })
    ),
  },
}

2. front부분, screens/Feed.js

import React, { useEffect, useState } from 'react'
import { FlatList } from 'react-native'
import styled from 'styled-components/native'
import { gql, useQuery } from '@apollo/client'
import useUser from '../useUser'
import ScreenLayout from '../components/ScreenLayout'
import Photo from '../components/Photo'

const Button = styled.TouchableOpacity`
  background-color: tomato;
  padding: 13px 10px;
  border-radius: 3px;
  width: 100%;
  opacity: ${(props) => (props.disabled ? '0.5' : '1')};
`
export const FEED_QUERY = gql`
  query seeFeed($offset: Int!) {
    seeFeed(offset: $offset) {
    ///1.  offset 값을 variables로 받도록 설정해 줌.
    
      id
      user {
        username
        avatar
      }
      file
      caption
      likes
      commentNumber
      createdAt
      isMine
      isLiked
      comments {
        id
        user {
          username
          avatar
        }
        payload
        isMine
        createdAt
      }
    }
  }
`
export default function Feed() {
  const User = useUser()
  console.log(User)
  const { data, loading, refetch, fetchMore } = useQuery(FEED_QUERY, {
  ///2. fetchMore를 useQuery에서 불러와줌.
  
    variables: {
      offset: 0,
      ///3. offset의 default 값은 0으로 설정해줌.
      
    },
  })
  const renderPhoto = ({ item: photo }) => {
    return <Photo {...photo} />
  }
  const refresh = async () => {
    setRefreshing(true)
    await refetch()
    setRefreshing(false)
  }
  const [refreshing, setRefreshing] = useState(false)
  return (
    <ScreenLayout loading={loading}>
      <FlatList
        onEndReachedThreshold={0.05}
        onEndReached={() =>
          fetchMore({
            variables: {
              offset: data?.seeFeed?.length,
            },
          })
        }
        /// 4. onEndReachedThreshold는 화면 어느부분에 갔을데 fetchMore할지 설정
        ///  값이 0이면 화면 맨 아래에 도달했을때, fetchMore가 이루어짐.
        /// 5. onEndReached는 함수를 받는데, onEndReachedThreshold에서 설정한
        /// 화면의 값에 도달하면 실행될 함수를 압력함.
        /// fetchMore를 실행시키고, variables의 offset은 맨처음 불려진 data 실이만큼
        /// 디시 loading한다는 의미, 2,3,4 아무거나 입력해도 상관 없음.
        
        refreshing={refreshing}
        onRefresh={refresh}
        style={{ width: '100%' }}
        showsVerticalScrollIndicator={false}
        data={data?.seeFeed}
        keyExtractor={(photo) => '' + photo.id}
        renderItem={renderPhoto}
      />
    </ScreenLayout>
  )
}

3. apollo.js

import {
  makeVar,
  ApolloClient,
  InMemoryCache,
  createHttpLink,
} from '@apollo/client'
import { setContext } from '@apollo/client/link/context'
import { offsetLimitPagination } from '@apollo/client/utilities'
import AsyncStorage from '@react-native-async-storage/async-storage'

export const isLoggedInVar = makeVar(false)
export const tokenVar = makeVar('')
export const TOKEN = 'token'

export const logUserIn = async (token) => {
  await AsyncStorage.setItem(TOKEN, token)
  isLoggedInVar(true)
  tokenVar(token)
}
export const logUserOut = async () => {
  await AsyncStorage.removeItem(TOKEN)
  isLoggedInVar(false)
  tokenVar(null)
}

const httpLink = createHttpLink({
  uri: 'http://10.0.2.2:4000/graphql',
})

const authLink = setContext((_, { headers }) => {
  return {
    headers: {
      ...headers,
      token: tokenVar(),
    },
  }
})

export const cache = new InMemoryCache({
  typePolicies: {
    Query: {
      fields: {
        seeFeed: offsetLimitPagination(),
      },
    },
  },
})
/// 마지막으로 InMemoryCache에 typePolicies:{ Query: {fields: {
///  에 infiniteScroll이 될 Query를 넣어준다음, offsetLimitPagination()을 넣어줌.


export const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache,
})
profile
코딩하는초딩쌤

0개의 댓글