Reputation: 351
I am creating an app using react router, with several routes including a Uploader
component where videos are uploaded, and a Videos
component where they are viewed. The video page stores some comments as state, which i want to remain on the page throughout the app being open. However, react router seems to be causing each component to re-mount rather than re-render, causing my state to be reset to the intial empty values whenever i re-route back to the Video
component. I'm using the render
method rather than the component
method inside my Route
components, so i don't understand why this is happening. Does anyone know whats causing this?
Here is the main app where routing occurs:
class App extends React.Component{
constructor(props){
super(props)
var fileNames
var files
var fileSelected
this.state={fileSelected:null}
}
getFileFromChild= (uploadedFiles)=> {
this.files = uploadedFiles
}
fileButtonClicked= (index)=> {
//extract file chosen by user based on button click
this.setState({fileSelected: this.files[0][index]})
}
render(){
//destructuring props in class component
const {user} = this.props;
return(
<Router>
<div className = "nav-bar">
<Nav/>
<Switch>
<Route path='/' exact render={()=> <HomePage />
}/>
<Route path='/videos' render={()=> <Videos files= {this.files} fileSelected={this.state.fileSelected}/>
}/>
<Route path='/uploader' render={()=> <Uploader passFile= {this.getFileFromChild} fileButtonClicked={this.fileButtonClicked}/>
} />
</Switch>
</div>
</Router>
)
}
}
Here is the Videos
component where the state i need is stored:
class Videos extends React.Component{
constructor(props){
super(props)
this.videoRef = React.createRef();
}
// once DOM loads get video tag and reload it
componentDidUpdate(){
this.videoRef.current.load()
}
render(){
const {files, fileSelected}=this.props;
var src = (fileSelected) ? URL.createObjectURL(fileSelected): URL.createObjectURL(files[0][0])
return(
<div>
<div className="ui one column centered grid">
<div className="one wide column"> {/*needs to be one wide here not just column for center to work*/}
<h3>Videos</h3>
</div>
</div>
<div className="ui grid">
<div className="ten wide column">
<video ref={this.videoRef} controls width="566" height="320">
<source src={src} id='video' type="video/mp4" />
Your browser does not support HTML5 video.
</video>
<CommentsSection/>
</div>
<div className="six wide column">
{files[1]}
</div>
</div>
</div>
)
}
}
Upvotes: 5
Views: 2060
Reputation: 2648
I don't exactly get what you mean by "when the Video
component is loaded more than once" but let me see if I can answer your question.
If you're saying that the Video
component is unmounted and mounted when you navigate(change route) away and back to it - resulting in losing the state of the Video
component you had - that is the expected behaviour of the render
method of Route
.
Let me explain in regards to the official docs on the react router page:
When you use component (instead of render or children, below) the router uses React.createElement to create a new React element from the given component. That means if you provide an inline function to the component prop, you would create a new component every render. This results in the existing component unmounting and the new component mounting instead of just updating the existing component. When using an inline function for inline rendering, use the render or the children prop...
What this means is:
render
or component
prop will always unmount and mount on route changerender
prop, it will not unmount and remount on every render - it will "remember" the inline function and not perform mount/unmountcomponent
prop, it will unmount and mount on every render - it will re-create the inline component on every render so it performs the unmounting of the old instance of the component and mounting of the newly created instance of the componentTakeaways:
component
and render
props will unmount on navigating away, and mount on navigating in, and that is the expected and desired behaviour.render
prop (e.g <Route render={() => <HomePage />}
)component
prop (e.g <Route component={HomePage} />
)component
proprender
component correctly. You just got confused with unmount and mounts on route change vs. prop changeUpvotes: 8