最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Why is React Router causing my components to re-mount, rather than just re-rendering? - Stack Overflow

programmeradmin1浏览0评论

I am creating an app using react router, with several routes including a Uploader ponent where videos are uploaded, and a Videos ponent where they are viewed. The video page stores some ments as state, which i want to remain on the page throughout the app being open. However, react router seems to be causing each ponent 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 ponent. I'm using the render method rather than the ponent method inside my Route ponents, 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 ponent
        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 ponent 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
    ponentDidUpdate(){
        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>

            )


    }
}

I am creating an app using react router, with several routes including a Uploader ponent where videos are uploaded, and a Videos ponent where they are viewed. The video page stores some ments as state, which i want to remain on the page throughout the app being open. However, react router seems to be causing each ponent 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 ponent. I'm using the render method rather than the ponent method inside my Route ponents, 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 ponent
        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 ponent 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
    ponentDidUpdate(){
        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>

            )


    }
}
Share Improve this question edited Sep 20, 2019 at 23:01 Sean Barker asked Sep 20, 2019 at 21:57 Sean BarkerSean Barker 3512 gold badges5 silver badges15 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 8

I don't exactly get what you mean by "when the Video ponent is loaded more than once" but let me see if I can answer your question.

If you're saying that the Video ponent is unmounted and mounted when you navigate(change route) away and back to it - resulting in losing the state of the Video ponent 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 ponent (instead of render or children, below) the router uses React.createElement to create a new React element from the given ponent. That means if you provide an inline function to the ponent prop, you would create a new ponent every render. This results in the existing ponent unmounting and the new ponent mounting instead of just updating the existing ponent. When using an inline function for inline rendering, use the render or the children prop...

What this means is:

  • ponent passed into either render or ponent prop will always unmount and mount on route change
  • if you pass an inline ponent into the render prop, it will not unmount and remount on every render - it will "remember" the inline function and not perform mount/unmount
  • if you passed an inline ponent into the ponent prop, it will unmount and mount on every render - it will re-create the inline ponent on every render so it performs the unmounting of the old instance of the ponent and mounting of the newly created instance of the ponent

Takeaways:

  • both ponent and render props will unmount on navigating away, and mount on navigating in, and that is the expected and desired behaviour.
  • you pass an inline ponent into render prop (e.g <Route render={() => <HomePage />})
  • you pass a ponent into ponent prop (e.g <Route ponent={HomePage} />)
  • never pass inline ponents into ponent prop
  • in your case, you're using the render ponent correctly. You just got confused with unmount and mounts on route change vs. prop change

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论