개발자

React state 변경시 PDF 깜빡거림 질문입니다!

2023년 04월 17일조회 416

안녕하세요. 현재 wojtekmaj / react-pdf 라이브러리를 사용해서 pdf 관련 개발을 하고 있습니다. + 버튼을 누르면 scale이 올라가고 - 버튼을 누르면 scale이 축소해서 pdf Page의 크기가 변하는데요. 여기서 발생하는 깜빡거림 (?) 을 없애고 싶습니다. 다른 분이 올려주신 질문글 (https://github.com/wojtekmaj/react-pdf/issues/875) 을 보고 페이지가 1개일때에는 해결이 되었는데. 제가 하고싶은 것은 페이지가 1개일 경우가 아닌 모든 페이지를 보여주고, 확대 축소가 발생했을 경우 깜빡거림이 일어나지 않도록 하고 싶습니다. 현재 제 코드에서는 간단하게 로딩상태 일 때 <></> Fragment만 추가해주어도 다시 깜빡거림이 발생하는데요.. 원인을 찾지 못하겠습니다... ( 현재 코드에서 Fragment만 제거하여도 깜빡거림은 사라집니다. ) 아래는 제 코드입니다. 관련하여 도움을 주실분 있으실까요,,?

1import { useEffect, useLayoutEffect, useState } from "react";
2import { pdfjs, Document, Page } from "react-pdf";
3import styled from "styled-components";
4
5pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`;
6
7const url = "pdf 주소"
8
9const Test = () => {
10    const [numPages, setNumPages] = useState(null);
11    const [scale, setScale] = useState<any>(1);
12    const [renderedScale, setRenderedScale] = useState<any>(null);
13
14    function onDocumentLoadSuccess({ numPages } : any) {
15        setNumPages(numPages);
16    }
17
18    function changeScale(offset : any) {
19    setScale((prevScale : any) => prevScale + offset);
20    }
21
22    function decreaseScale() {
23    changeScale(-0.1);
24    }
25
26    function increaseScale() {
27    changeScale(0.1);
28    }
29
30    const isLoading =  renderedScale !== scale;
31
32    return (
33        <Wrapper>
34        <div className="App">
35        <div>
36        <p>Scale {scale}</p>
37
38        <button type="button" disabled={scale <= 0.5} onClick={decreaseScale}>
39            -
40        </button>
41
42        <input
43            type="range"
44            min="0.5"
45            max="2"
46            value={scale}
47            onChange={(event) => setScale(Number(event.target.value))}
48            step="0.1"
49        />
50
51        <button type="button" disabled={scale >= 2} onClick={increaseScale}>
52            +
53        </button>
54        </div>
55        <Container>
56        <Document file={url} onLoadSuccess={onDocumentLoadSuccess}>
57
58            {isLoading ? (  
59                    <>
60                        <Page
61                            key={"@" + renderedScale}
62                            className="prevPage"
63                            pageNumber={1}
64                            scale={renderedScale}
65                        />
66                    </>
67                ) : null}
68            
69            <Page
70                key={ "@" + scale}
71                pageNumber={1}
72                onRenderSuccess={() => {
73                    setRenderedScale(scale);
74                }}
75                scale={scale}
76            />
77            
78        </Document>
79        </Container>
80
81    </div>
82    </Wrapper>
83    );
84};
85
86
87
88
89
90
91
92
93export default Test;
94
95const Wrapper = styled.div`
96    background-color: rgba(0, 0, 0, 0.5);
97    width: 100%;
98    height: 100vh;
99    .App {
100    }
101
102    button {
103        padding: 20px;
104        background-color: blue;
105    }
106
107    canvas {
108        margin: 0 auto;
109    }
110`
111
112const Container = styled.div`
113`
이 질문이 도움이 되었나요?
'추천해요' 버튼을 누르면 좋은 질문이 더 많은 사람에게 노출될 수 있어요. '보충이 필요해요' 버튼을 누르면 질문자에게 질문 내용 보충을 요청하는 알림이 가요.

답변 1

커리어리 AI 봇님의 프로필 사진

안녕하세요! 깜빡거림 문제를 해결해 드리겠습니다. ' react-pdf '의 ' Page ' 컴포넌트가 새로 렌더링 될 때마다 문제가 발생하므로, 이를 방지하기 위해 각 페이지를 캐싱해 두고 확대/축소를 수행하려고 합니다. 이를 위해 ' useRef ' 훅을 사용하여 각 페이지를 DOM에 저장하고, ' useEffect ' 훅을 사용하여 ' scale '이 변경되었을 때 페이지의 스타일을 업데이트하겠습니다. 다음은 수정된 코드입니다 이제 모든 페이지가 한 번만 렌더링되어 캐싱되고, 확대/축소 작업이 수행될 때 DOM 요소의 스타일만 업데이트하므로 깜빡거림이 발생하지 않아야 합니다. 이를 통해 깜빡거림 문제를 해결할 수 있습니다. 코드에 다음과 같은 변경 사항을 적용했습니다: 1. ' useRef '를 사용하여 ' pagesRef '를 생성하고, 이를 통해 각 페이지의 DOM 요소에 대한 참조를 저장합니다. 2. ' Page ' 컴포넌트에 ' inputRef ' prop을 추가하여 각 페이지의 DOM 요소에 대한 참조를 ' pagesRef '에 저장합니다. 이렇게 하면 렌더링된 페이지를 참조할 수 있게 됩니다. 3. ' useEffect '를 사용하여 ' scale '이 변경되었을 때 각 페이지의 스타일을 업데이트합니다. 이렇게 하면 확대/축소 작업을 수행할 때 새로운 렌더링이 발생하지 않고, DOM 요소의 스타일만 업데이트됩니다. 이 수정을 적용한 결과, 모든 페이지가 한 번만 렌더링되어 캐싱되고, 확대/축소 작업이 수행될 때 깜빡거림이 발생하지 않게 되었습니다. 이로써 문제를 해결할 수 있었습니다. 만약 추가적인 도움이 필요하시거나 다른 질문이 있으시면 언제든지 알려주세요!

1import { useEffect, useRef, useState } from "react";
2import { pdfjs, Document, Page } from "react-pdf";
3import styled from "styled-components";
4
5pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`;
6
7const url = "pdf 주소";
8
9const Test = () => {
10  const [numPages, setNumPages] = useState(null);
11  const [scale, setScale] = useState<any>(1);
12
13  const pagesRef = useRef<any[]>([]);
14
15  function onDocumentLoadSuccess({ numPages }: any) {
16    setNumPages(numPages);
17  }
18
19  function changeScale(offset: any) {
20    setScale((prevScale: any) => prevScale + offset);
21  }
22
23  function decreaseScale() {
24    changeScale(-0.1);
25  }
26
27  function increaseScale() {
28    changeScale(0.1);
29  }
30
31  useEffect(() => {
32    pagesRef.current.forEach((page: any) => {
33      if (page) {
34        page.style.transform = `scale(${scale})`;
35      }
36    });
37  }, [scale]);
38
39  return (
40    <Wrapper>
41      <div className="App">
42        <div>
43          <p>Scale {scale}</p>
44
45          <button
46            type="button"
47            disabled={scale <= 0.5}
48            onClick={decreaseScale}
49          >
50            -
51          </button>
52
53          <input
54            type="range"
55            min="0.5"
56            max="2"
57            value={scale}
58            onChange={(event) => setScale(Number(event.target.value))}
59            step="0.1"
60          />
61
62          <button
63            type="button"
64            disabled={scale >= 2}
65            onClick={increaseScale}
66          >
67            +
68          </button>
69        </div>
70        <Container>
71          <Document file={url} onLoadSuccess={onDocumentLoadSuccess}>
72            {Array.from(new Array(numPages), (_, index) => (
73              <Page
74                key={`page_${index + 1}`}
75                inputRef={(page: any) => {
76                  pagesRef.current[index] = page;
77                }}
78                pageNumber={index + 1}
79                scale={1}
80              />
81            ))}
82          </Document>
83        </Container>
84      </div>
85    </Wrapper>
86  );
87};
88
89export default Test;
90
91const Wrapper = styled.div`
92  background-color: rgba(0, 0, 0, 0.5);
93  width: 100%;
94  height: 100vh;
95  .App {
96  }
97
98  button {
99    padding: 20px;
100    background-color: blue;
101  }
102
103  canvas {
104    margin: 0 auto;
105  }
106`;
107
108const Container = styled.div``;

커리어리 AI 봇의 답변을 평가해 주세요!

지금 가입하면 모든 질문의 답변을 볼 수 있어요!

현직자들의 명쾌한 답변을 얻을 수 있어요.

또는

이미 회원이신가요?

목록으로

지금 가입하면 모든 질문의 답변을 볼 수 있어요!