magic_turtle
magic_turtle

Reputation: 1333

react-file-viewer does not load a new document on filePath change

I am using react-file-viewer in React.js app to read docx. I use a template code. I can read the file, but as soon as I dynamically change the filePath - FileViewer does not reload. I can see that my component gets updated with a new filePath, and I can render a new filePath in a container code, so it gets displayed on screen, but the actual FileViewer does not re-render and displays previously loaded document.

Upvotes: 0

Views: 6884

Answers (5)

Mohammad Atiour Islam
Mohammad Atiour Islam

Reputation: 5708

In your dynamically change filepath event you can make your file path empty then set the new file path.

 constructor() {
      this.state = {      
      filePreviewPath: "",
      filePreviewType: "",
    };
  }


// dynamic load event           
    this.setState({           
      filePreviewPath: "",
      filePreviewType: ""
    });

    this.setState({
      filePreviewPath: filePathDataUrl, // filePathDataUrl: string = "data:" + mimeTypeforPreview + ";base64, " + fileObj.fileContent;
      filePreviewType: filePreviewType  // filePreviewType = "pdf"
    });

html

<FileViewer
  fileType={this.state.filePreviewType}
  filePath={this.state.filePreviewPath}
/>

Upvotes: 0

Sohail Arif
Sohail Arif

Reputation: 69

make sure to pass unique key if u have multiple documents you want to display.

something like

const FileViewerComponent = (props) => {

const [state, setState] = useState({
    type: getFileExtension(props.file.Title),
    path: getFilePath(props.file.Path)
});
useEffect(() => {
    if (state.path != getFilePath(props.file.Path)) {
        setState({
            type: getFileExtension(props.file.Title),
            path: getFilePath(props.file.Path)
        })
    }
});

return (<div style={{maxHeight: '700px', 'overflow-y': 'scroll'}}>
        <FileViewer 
          fileType={state.type} 
          filePath={state.path} 
          key= {state.path}
       />
    </div>
);

};

Upvotes: 1

Terrence Tran
Terrence Tran

Reputation: 11

Hi I had the same issue and I managed to fix it by adding a dynamic key to the FileViewer: This will rerender the component each times the filePath changes.

<FileViewer
        key={this.props.filePath}
        fileType='docx'
        filePath={path.resolve(__dirname), `path/${this.props.filePath}`}
        etc.
/>

Upvotes: 1

Cafer Elgin
Cafer Elgin

Reputation: 423

You should wrap the file viewer component with a div and provide a key which can be a random number:

return(
    <div key={Math.random()}>
        <FileViewer
            fileType={filetype}
            filePath={path}
            etc.
        />
    </div>
)

Upvotes: 3

magic_turtle
magic_turtle

Reputation: 1333

Managed to get it working by forcing unmounting of the container that wraps <File Viewer /> as on initial mount the document was loading properly and the only time it was not working was on a re-render. To unmount, I used a key attribute as described here by T.J. Crowder.

// Parent.js
return (
    <div>
        {this.state.filePath && <FileViewerWrapper filePath={this.state.filePath} />}
    <div>
);

// Child.js
render(){
    ++this.childKey; // initialized in constructor
    return (
        <FileViewer
            fileType='docx'
            filePath={path.resolve(__dirname), `path/${this.props.filePath}`}
            etc.
        />
    );
}

As from the linked answer -

The child will have a new key each time, so React will assume it's part of a list and throw away the old one, creating the new one. Any state change in your component that causes it to re-render will force that unmount-and-recreated behavior on the child.

P.S. Initially I tried to use unmountComponentAtNode method from ReactDOM with a ref on a Child component. Something like this -

  let mountNode = ReactDOM.findDOMNode(this.refs.mount);

  try {
    ReactDOM.unmountComponentAtNode(mountNode);
  } catch (e) {
    console.error(e);
  }

but was getting a warning unmountComponentAtNode(): The node you're attempting to unmount was rendered by React and is not a top-level container. Instead, have the parent component update its state and rerender in order to remove this component. So, the solution with key works for me better.

Upvotes: 1

Related Questions