Reactjs 不断对PDF查看器组件重新加载作出反应

Reactjs 不断对PDF查看器组件重新加载作出反应,reactjs,react-pdf,Reactjs,React Pdf,我在我的项目中使用了一个。我有一个可以拖动的工具 import React from "react"; import withStyles from "@material-ui/core/styles/withStyles"; import makeStyles from "@material-ui/core/styles/makeStyles"; import DialogContent from "@material-ui

我在我的项目中使用了一个。我有一个可以拖动的工具

import React from "react";
import withStyles from "@material-ui/core/styles/withStyles";
import makeStyles from "@material-ui/core/styles/makeStyles";
import DialogContent from "@material-ui/core/DialogContent";
import IconButton from "@material-ui/core/IconButton";
import ClearIcon from "@material-ui/icons/Clear";
import Draggable from "react-draggable";
import Paper from "@material-ui/core/Paper";
import Dialog from "@material-ui/core/Dialog";
import PDFViewer from "./PDFViewer";

function PaperComponent({...props}) {
  return (
    <Draggable
    >
      <Paper {...props} />
    </Draggable>
  );
}

const StyledDialog = withStyles({
  root: {
    pointerEvents: "none"
  },
  paper: {
    pointerEvents: "auto"
  },
  scrollPaper: {
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'flex-end',
    marginRight: 20
  }
})(props => <Dialog hideBackdrop {...props} />);

const useStyles = makeStyles({
  dialog: {
    cursor: 'move'
  },
  dialogContent: {
    '&:first-child': {
      padding: 10,
      background: 'white'
    }
  },
  clearIcon: {
    position: 'absolute',
    top: -20,
    right: -20,
    background: 'white',
    zIndex: 1,
    '&:hover': {
      background: 'white'
    }
  },
  paper: {
    overflowY: 'visible',
    maxWidth: 'none',
    maxHeight: 'none',
    width: 550,
    height: 730
  }
});

const PDFModal = (props) => {
  const classes = useStyles();
  const {open, onClose, pdfURL} = props;
  return (
    <StyledDialog
      open={open}
      classes={{root: classes.dialog, paper: classes.paper}}
      PaperComponent={PaperComponent}
      aria-labelledby="draggable-dialog"
    >
      <DialogContent classes={{root: classes.dialogContent}} id="draggable-dialog">
        <IconButton className={classes.clearIcon} aria-label="Clear" onClick={onClose}>
          <ClearIcon/>
        </IconButton>
        <PDFViewer
          url={pdfURL}
        />
      </DialogContent>
    </StyledDialog>
  );
};


export default PDFModal;
从“React”导入React;
从“@material ui/core/styles/withStyles”导入withStyles;
从“@material ui/core/styles/makeStyles”导入makeStyles;
从“@material ui/core/DialogContent”导入DialogContent;
从“@material ui/core/IconButton”导入图标按钮;
从“@material ui/icons/Clear”导入ClearIcon;
从“react Draggable”导入Draggable;
从“@material ui/core/Paper”导入纸张;
从“@material ui/core/Dialog”导入对话框;
从“/PDFViewer”导入PDFViewer;
函数PaperComponent({…props}){
返回(
);
}
const StyledDialog=带样式({
根目录:{
pointerEvents:“无”
},
论文:{
指针事件:“自动”
},
卷轴纸:{
显示:“flex”,
对齐项目:“居中”,
justifyContent:“柔性端”,
marginRight:20
}
})(道具=>);
const useStyles=makeStyles({
对话框:{
光标:“移动”
},
对话内容:{
“&:第一个孩子”:{
填充:10,
背景:“白色”
}
},
clearIcon:{
位置:'绝对',
前-20名,
右:-20,
背景:“白色”,
zIndex:1,
“&:悬停”:{
背景:“白色”
}
},
论文:{
溢出:“可见”,
maxWidth:“无”,
maxHeight:“无”,
宽度:550,
身高:730
}
});
常量PDFModal=(道具)=>{
const classes=useStyles();
const{open,onClose,pdfURL}=props;
返回(
);
};
导出默认PDFModal;
这是PDFViewer组件:

import React from 'react';
import { Viewer, SpecialZoomLevel, Worker  } from '@react-pdf-viewer/core';
import { defaultLayoutPlugin } from '@react-pdf-viewer/default-layout';

import '@react-pdf-viewer/core/lib/styles/index.css';
import '@react-pdf-viewer/default-layout/lib/styles/index.css';
import ArrowForward from "@material-ui/icons/ArrowForward";
import ArrowBack from "@material-ui/icons/ArrowBack";
import Button from "@material-ui/core/Button";
import IconButton from "@material-ui/core/IconButton";
import RemoveCircleOutlineIcon from '@material-ui/icons/RemoveCircleOutline';
import AddCircleOutlineIcon from '@material-ui/icons/AddCircleOutline';
import './PDFViewer.css';

const PDFViewer = ({url}) => {
  const renderToolbar = (Toolbar) => (
    <Toolbar>
      {
        (slots) => {
          const {
            CurrentPageLabel, CurrentScale, GoToNextPage, GoToPreviousPage, ZoomIn, ZoomOut,
          } = slots;
          return (
            <div
              style={{
                alignItems: 'center',
                display: 'flex',
              }}
            >
              <div style={{ padding: '0px 2px' }}>
                <ZoomOut>
                  {
                    (props) => (
                      <IconButton aria-label="delete" onClick={props.onClick}>
                        <RemoveCircleOutlineIcon />
                      </IconButton>
                    )
                  }
                </ZoomOut>
              </div>
              <div style={{ padding: '0px 2px' }}>
                <CurrentScale>
                  {
                    (props) => (
                      <span>{`${Math.round(props.scale * 100)}%`}</span>
                    )
                  }
                </CurrentScale>
              </div>
              <div style={{ padding: '0px 2px' }}>
                <ZoomIn>
                  {
                    (props) => (
                      <IconButton aria-label="delete" onClick={props.onClick}>
                        <AddCircleOutlineIcon />
                      </IconButton>
                    )
                  }
                </ZoomIn>
              </div>
              <div style={{ padding: '0px 2px', marginLeft: 'auto' }}>
                <GoToPreviousPage>
                  {
                    (props) => (
                      <Button
                        style={{
                          cursor: props.isDisabled ? 'not-allowed' : 'pointer',
                          height: '30px',
                          width: '30px'
                        }}
                        disabled={props.isDisabled}
                        disableElevation
                        disableFocusRipple
                        onClick={props.onClick}
                        variant="outlined">
                        <ArrowBack fontSize="small"/>
                      </Button>
                    )
                  }
                </GoToPreviousPage>
              </div>
              <div style={{ padding: '0px 2px' }}>
                <CurrentPageLabel>
                  {
                    (props) => (
                      <span>{`${props.currentPage + 1} av ${props.numberOfPages}`}</span>
                    )
                  }
                </CurrentPageLabel>
              </div>
              <div style={{ padding: '0px 2px' }}>
                <GoToNextPage>
                  {
                    (props) => (
                      <Button
                        style={{
                          cursor: props.isDisabled ? 'not-allowed' : 'pointer',
                          height: '30px',
                          width: '30px'
                        }}
                        disabled={props.isDisabled}
                        disableElevation
                        disableFocusRipple
                        onClick={props.onClick}
                        variant="outlined">
                        <ArrowForward fontSize="small"/>
                      </Button>
                    )
                  }
                </GoToNextPage>
              </div>
            </div>
          )
        }
      }
    </Toolbar>
  );

  const defaultLayoutPluginInstance = defaultLayoutPlugin({
    renderToolbar,
    sidebarTabs: defaultTabs => [defaultTabs[1]]
  });

  // constantly called
  console.log('entered')
  return (
    <div
      style={{
        height: '100%',
      }}
    >
      <Worker workerUrl="https://unpkg.com/pdfjs-dist@2.5.207/build/pdf.worker.min.js">
        <Viewer
          fileUrl={url}
          defaultScale={SpecialZoomLevel.PageFit}
          plugins={[
            defaultLayoutPluginInstance
          ]}
        />
      </Worker>
    </div>
  );
};

export default PDFViewer;
从“React”导入React;
从'@react pdf Viewer/core'导入{Viewer,SpecialZoomLevel,Worker};
从'@react pdf viewer/default layout'导入{defaultLayoutPlugin};
导入“@react pdf viewer/core/lib/styles/index.css”;
导入“@react pdf viewer/default layout/lib/styles/index.css”;
从“@material ui/icons/ArrowForward”导入ArrowForward”;
从“@material ui/icons/ArrowBack”导入箭头;
从“@物料界面/核心/按钮”导入按钮;
从“@material ui/core/IconButton”导入图标按钮;
从“@material ui/icons/RemoveCircleOutline”导入RemoveCircleOutlineIcon;
从“@material ui/icons/AddCircleOutline”导入AddCircleOutlineIcon;
导入“/PDFViewer.css”;
const PDFViewer=({url})=>{
const renderToolbar=(工具栏)=>(
{
(插槽)=>{
常数{
CurrentPageLabel、CurrentScale、GoToNextPage、GoToPreviousPage、ZoomIn、ZoomOut、,
}=插槽;
返回(
{
(道具)=>(
)
}
{
(道具)=>(
{${Math.round(props.scale*100)}%`}
)
}
{
(道具)=>(
)
}
{
(道具)=>(
)
}
{
(道具)=>(
{`${props.currentPage+1}av${props.numberOfPages}`}
)
}
{
(道具)=>(
)
}
)
}
}
);
const defaultLayoutPluginInstance=defaultLayoutPlugin({
伦德托巴尔,
sidebarTabs:defaultTabs=>[defaultTabs[1]]
});
//经常打电话
console.log('entered')
返回(
);
};
导出默认PDFViewer;

我可以在控制台中看到PDFViewer不断被调用。我不确定是什么原因导致了这种重新渲染?

当您将一个新的
文件URL
传递给
PDFModal
时,重新渲染是否有意义?下面的顺序应该是应用程序的执行方式

  • PDFModal
    PDFViewer
    和其他相关组件初始化
  • 将文件拖到
    PaperComponent
    上下文中时,上层组件将处理该文件并作为道具传递
    pdfURL
  • 我同意@LindaPaiste所说的,将
    工具栏
    作为一个选项,因为它不使用传入的
    url
    道具。对于重新渲染问题,我建议可以使用
    useCallback
    包装整个
    PDFViewer
    组件。仅当
    url
    发生更改时才更新组件

    这为何时使用
    useCallback
    提供了一些见解,可以作为参考

    const PDFViewer = useCallback(
        ({ url }) => {
            //...skipped code
            return (
                //...skipped code
                <Viewer
                    fileUrl={url}
                />
            )
    }, [url])
    
    const PDFViewer=useCallback(
    ({url})=>{
    //…跳过了代码
    返回(
    //…跳过了代码
    )
    },[url])
    
    我会尝试在
    PDFViewer
    之外定义你的
    renderToolbar
    函数,看看这是否有帮助。你能提供一个codesandbox吗?@宏我在codesandbox中也尝试过同样的方法:我所能看到的是它没有频繁调用
    控制台.log(entered)
    <代码>(仅供参考-我已将console.log(已输入)更改为console.error(已输入)在该代码沙盒中)
    const PDFViewer = ({ url }) => {
       //...skipped code
       return (
           //...skipped code
           <Viewer
              fileUrl={url}
           />
       );
    }
    
    const PDFViewer = useCallback(
        ({ url }) => {
            //...skipped code
            return (
                //...skipped code
                <Viewer
                    fileUrl={url}
                />
            )
    }, [url])