React注册路由表component与render的区别?

601 阅读3分钟

1)路由组件文件

import React,{ Component } from "react";


export default class Main extends Component {

    constructor(props) {
        super(props);
        console.log("Main 执行构造函数!!!!");
    }
    
    getUserId = ()=> {
        let {
          match: {
              params:{id}
          }
      } =  this.props
      return id
    }
    componentDidMount() {
        let userId = this.getUserId()
       console.log('挂载完成===',userId)
    }

    componentDidUpdate() {
         let userId = this.getUserId()
       console.log('更新完成===',userId)
    }
    render() {
        console.log('render')
       let userId = this.getUserId()
        return (
            <div>
                <div>页面{userId}数据</div>
            </div>

        )
    }
}

2)App组件文件

import React,{ Component } from "react";
import { Link,Route,Switch,Redirect } from "react-router-dom";
import "./App.css";
import Main from "./components/Main";
export default class App extends Component {
    state = {count:0}
    handleRender = ()=> {
        console.log('将要render父组件')
        this.setState({
            count: this.state + 1
        })
    }
    render(){
        console.log('App 执行render。。。')
        return (
            <div className="app">
                app....
                <div>
                    <button onClick={this.handleRender}>执行父组件render</button>
                </div>
                <Link to="/mylist/userA"> 展示用户A</Link>
                <Link to="/mylist/userB"> 展示用户B</Link>

                {/* component直接》注册路由表 */}
                <Route path="/mylist/:id" component={Main}/>

                {/* component 》回调函数注册路由表 */}
                {/* <Route path="/mylist/:id" component={(props)=>{
                    return(
                    // <Main key={props.match.params.id} {...props}/>
                    <Main {...props}/>
                )
                }}/> */}

                {/* <Route path="/mylist/:id" render={(props)=>{
                    return(
                    // <Main key={props.match.params.id} {...props}/>
                    <Main {...props}/>
                )
                }}/> */}
                
                
                <Redirect to="/mylist/userA"/>
            </div>
        )
    }
}

结果:

  • (1) component直接注册路由表:

    <Route path="/mylist/:id" component={Main}/>
    
    • 在点击路由切换的时候,只触发【组件的更新】,没有触发组件的【挂载完成】,可以知道触发了【组件的更新

    • 这种方式在App组件render方法再执行时,不会造成Main组件重新渲染,只是update,缺点:不能从父组件传递props到子组件,可以在子组件访问路由属性。

  • (2)component 使用return组件来注册路由表:

    • 第一种情况,路由组件没有使用属性key

        <Route path="/mylist/:id" component={(props)=>{
            return(
            	<Main {...props}/>
        	)
        }}/>
      
      • 在点击路由切换的时候,只触发【组件的更新】,没有触发组件的【挂载完成】,可以知道触发了【组件的更新】,props参数是路由组件的路由信息

      • 这种方式会造成每次App组件重新render时候Main组件都会重新执行一次初始化生命周期,而不是执行update,,但是它能够传递入参作为Mainprops,可以访问路由属性,但是需要在函数指定入参,然后标记传递到子组件

    • 第二种情况,路由组件使用了属性key

      <Route path="/mylist/:id" component={(props)=>{
          return(
              <Main key={props.match.params.id} {...props}/>
          )
      }}/>
      
      • 在点击路由切换的时候,只触发【挂载完成】,没有触发组件的【组件的更新】,可以知道触发了【组件的挂载】,props参数是路由组件的路由信息

      • App组件 render触发时,结果和不带属性key是一样的

    • 第三种情况,路由组件不带任何参数

      定义一个路由组件Test

      import React,{ Component } from "react";
      
      export default class Test extends Component {
           constructor(props) {
               super(props);
               console.log("Test 执行构造函数!!!!");
         }
         componentDidMount() {
              console.log('Test》挂载完成')
           }
           componentDidUpdate(precProp) {
              console.log('Test》更新完成')
           }
           render() {
               return (
                   <div>
                       <div>Test组件</div>
                   </div>
               )
           }
       }
      

      App组件文件核心代码如下:

        <Route path="/mylist/:id" component={(props)=>{
           return(
           <Test/>
       )
       }}/>
      
      • 在点击路由切换的时候,只触发【组件的更新】,没有触发组件的【挂载完成】,可以知道触发了【组件的更新】,props参数是路由组件的路由信息

      • App组件 render触发时,结果和不带属性key是一样的

  • (3)Route标签里直接写路由组件Test

      <Route path="/mylist/:id">
          <Test/>
      </Route>
    
    • 点击路由,不触发钩子函数
    • 这种方式每次(第一次除外)App执行render不会造成Main重新执行一次初始化生命周期,只会执行update的生命钩子,可以从父组件传递props到子组件,但是这个方式有一个缺点,子组件不能在props访问路由属性
  • (4)render方法

    <Route path="/mylist/:id" render={(props)=>{
        return(
        // <Main key={props.match.params.id} {...props}/>
        <Main {...props}/>
    )
    }}/>
    
    • 路由组件不带key属性:

      • 在点击路由切换的时候,只触发【组件的更新】,没有触发组件的【挂载完成】,可以知道触发了【组件的更新】,props参数是路由组件的路由信息

      • 这种方式每次(第一次除外)App执行render不会造成Main重新执行一次初始化生命周期,只会执行update的生命钩子,可以从父组件传递props到子组件,但是这个方式有一个缺点,子组件不能在props访问路由属性

    • 路由组件带key属性:

      • 在点击路由切换的时候,触发【挂载完成】【路由组件的构造函数】,没有触发组件的【组件的更新】,可以知道触发了【挂载完成】,props参数是路由组件的路由信息
    • App组件 render触发时,结果和不带属性key是一样的