Reputation: 1333
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
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
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
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
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
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