inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

Slack 클론 코딩[실시간 채팅 with React]

스크롤바 조절하기

infinite scroll에서 최초 랜더링한 페이지가 한페이지에 안나올때 추가로 페이지를 불러 올수 있나요?

해결된 질문

552

최석우

작성한 질문수 20

0

만약 Page의 단위를 5로 잡아서
최초 랜더링한 페이지가 스크롤이 되지않는다면
onScroll 이벤트가 발생하지 않으니 setSize 이벤트도 발생할수 없습니다.
이렇게 최초 데이터의 개수가 모자라서 이벤트 자체가 발생하지 않으면 별개의 이벤트로 scroll이 가능할때까지 페이지를 불러와야 하는데 좋은 방법이 잇는가요?

페이지를 5개로 잡을떄

페이지를 20개로 잡을떄

참조 코드

import ChatBox from '@components/ChatBox';
import ChatList from '@components/ChatList';
import useInput from '@hooks/useInput';
import { Header, Container } from '@pages/DirectMessage/styles';
import fetcher from '@utils/fetcher';
import makeSection from '@utils/makeSection';
import axios from 'axios';
import gravatar from 'gravatar';
import React, { FC, FormEventHandler, useCallback, useEffect, useRef, useState } from 'react';
import Scrollbars from 'react-custom-scrollbars-2';
import { useParams } from 'react-router';
import useSWR from 'swr';
import useSWRInfinite from 'swr/infinite';

const PAGE_SIZE = 5;

const DirectMessage: FC = () => {
  const { workspace, id } = useParams();
  const { data: myData } = useSWR<IUser, false>('/api/users', fetcher);
  const { data: userData } = useSWR<IUser, false>(`/api/workspaces/${workspace}/users/${id}`, fetcher);

  const [chat, onChangeChat, setChat] = useInput('');
  // const scrollbarRef = useRef(null);
  const {
    data: chatData,
    mutate: mutateChat,
    setSize,
  } = useSWRInfinite<IDM[]>(
    (index) => `/api/workspaces/${workspace}/dms/${id}/chats?perPage=${PAGE_SIZE}&page=${index + 1}`,
    fetcher,
  );

  const isEmpty = chatData?.[0]?.length === 0;
  const isReachingEnd = isEmpty || (chatData && chatData[chatData.length - 1]?.length < PAGE_SIZE);
  const chatSection = makeSection(chatData ? [...chatData].flat().reverse() : []);

  const onSubmitForm = useCallback<FormEventHandler>(
    (event) => {
      event.preventDefault();

      if (!chat || !chat?.trim()) {
        return;
      }

      axios
        .post(`/api/workspaces/${workspace}/dms/${id}/chats`, {
          content: chat,
        })
        .then(() => {
          mutateChat();
          setChat('');
        })
        .catch(console.error);

      console.log('제출');
    },
    [chat, id, mutateChat, setChat, workspace],
  );

  const scrollbarRef = useRef<Scrollbars>(null);

  return !userData || !myData || !chatData ? null : (
    <Container>
      <Header>
        <img src={gravatar.url(userData.email, { s: '24px', d: 'retro' })} alt={userData.nickname} />
        <span>{userData.nickname}</span>
      </Header>
      <ChatList
        chatSections={chatSection}
        isEmpty={isEmpty}
        isReachingEnd={isReachingEnd}
        setSize={setSize}
        ref={scrollbarRef}
      />
      <ChatBox
        onSubmitForm={onSubmitForm}
        chat={chat}
        onChangeChat={onChangeChat}
        placeholder={`Message ${userData.nickname}`}
        otherData={[userData]}
      />
    </Container>
  );
};

export default DirectMessage;
import Chat from '@components/Chat';
import { ChatZone, Section, StickyHeader } from '@components/ChatList/styles';
import React, { FC, MutableRefObject, forwardRef, useCallback } from 'react';
import { Scrollbars, positionValues } from 'react-custom-scrollbars-2';

interface Props {
  chatSections: { [key: string]: (IDM | IChat)[] };
  isEmpty: boolean;
  isReachingEnd?: boolean;
  setSize: (f: (size: number) => number) => Promise<(IDM | IChat)[][] | undefined>;
}
const ChatList = forwardRef<Scrollbars, Props>(({ chatSections, isReachingEnd, isEmpty, setSize }, scrollRef) => {
  const onScroll = useCallback(
    (values: positionValues) => {
      if (values.scrollTop === 0 && !isReachingEnd) {
        setSize((size) => size + 1).then(() => {
          const current = (scrollRef as MutableRefObject<Scrollbars>)?.current;
          if (current) {
            current.scrollTop(current.getScrollHeight() - values.scrollHeight);
          }
        });
      }
    },
    [isReachingEnd, scrollRef, setSize],
  );

  return (
    <ChatZone>
      <Scrollbars autoHide ref={scrollRef} onScrollFrame={onScroll}>
        {Object.entries(chatSections).map(([dateData, chatData]) => (
          <Section className={`section-${dateData}`} key={dateData}>
            <StickyHeader>
              <button>{dateData}</button>
            </StickyHeader>
            {chatData.map((chat) => (
              <Chat key={chat.id} data={chat} />
            ))}
          </Section>
        ))}
      </Scrollbars>
    </ChatZone>
  );
});

export default ChatList;

 

react 웹팩 typescript socket.io babel 클론코딩

답변 1

1

제로초(조현영)

처음 불러올 때만 많이 불러오고 그 다음에는 5개씩 불러오면 안 되나요?

0

최석우

세로 모니터를 쓰거나 모바일에서 보는등 예외 케이스가 존재할 수 있을거 같아서 처리하고 싶엇습니다.

0

제로초(조현영)

초기 로딩전략과 스크롤이생기고 난 후의 전략을 다르게하면 되는건 마찬가지입니다. 초기에는 스크롤이 생길때까지 반복적으로 불러오기 + 스크롤이 생긴 후에는 내릴 때 불러오기 해야할 것 같네요.

기본 셋팅과 관련하여

0

92

1

초기 셋팅 back과 front만 남겨두고 다 지운 후 진행 방법

0

96

2

focus 시에만 화면 업데이트 되는 이유 + 해결방법

0

150

2

useEffect 개수 관리

0

110

2

라이브러리 서치 방법

0

104

2

함수 정의 패턴

0

77

1

npm run dev 에러

0

152

3

npx webpack 후 에러

0

178

2

'void' 형식 식의 truthiness를 테스트할 수 없습니다.ts(1345)

0

144

2

사용자 가입시 에러발생 (TypeError: Cannot read properties of null (reading 'addMembers')

1

178

2

초기세팅중 packge.json 에러떠요

0

156

2

CORS - Access-Control-Allow-Origin 누락 문제

0

431

3

로그인 페이지 무한 새로고침 현상

0

598

2

Module not found: Error: Can't resolve './App' 에러

0

959

1

배포 방법

0

297

2

npm run dev 시 빌드가 매우 느려졌습니다

0

990

2

alias 경로 설정 오류

0

451

2

fetcher 함수의 data 값이 두번 찍히는 이유

0

277

1

제네릭 질문

0

218

2

ts-node 대신 tsx 사용여부

0

373

1

배포 관련 질문

0

247

1

[nginx + https] 서비스를 실행하면 niginx가 아닌 서비스 화면을 보여주게 하고 싶습니다.

0

385

2

[배포하기] webpack에 aws 퍼블릭 IPv4 주소 와 포트 주소를 작성하고 나서 빌드후 실행하면 오류가 발생합니다.

0

336

1

users 호출 시 쿠키가 담기지 않는 이슈 질문드립니다.

0

247

2