react-router 4.x中, component 渲染方式和render 渲染方式的不同

1, 问题来源

react-router 官网文章 中 有这样一段话

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 (below).

翻译过来就是:(本博客与谷歌翻译达成深度合作)

当您使用component(而不是下面的render或children)时,路由器将使用React.createElement给定的组件创建一个新的React元素。这意味着,如果为componentprop 提供内联函数,则将在每个渲染器中创建一个新组件。这将导致现有组件的卸载和新组件的安装,而不仅仅是更新现有组件。当使用内联函数进行内联渲染时,请使用render或children道具(如下)。

2, 误入歧途

2.1 刚开始的时候,将重点放在了 “现有组件的卸载和新组件的安装”,“重新渲染” 这些子句上面。将其yy为 “路由组件的懒加载,即来回切换路由组件,会保存路由组件的状态,而不会重新渲染路由组件”。
          下面的模拟的demo code: (react版本- 16.10)

import React,{Component} from 'react';
import { BrowserRouter , Route , Switch , Link} from 'react-router-dom';

class Home extends React.Component {
    componentDidMount() {
        console.log("Home componentDidMount")
    }
    componentWillUnmount() {
        console.log("Home componentWillUnmount")
    }
    render() {
        return (
            <div></div>
        )
    }
}

class Admin extends React.Component {
    componentDidMount() {
        console.log("Admin componentDidMount")
    }
    componentWillUnmount() {
        console.log("Admin componentWillUnmount")
    }
    render() {
        return (
            <div></div>
        )
    }
}

class Router extends Component{
    render(){
        return (
            <BrowserRouter>
                <Link to="/home">跳转home</Link>
                <Link to="/admin">跳转admin</Link>
                <Switch>
                    <Route path="/home" exact render={() => <Home/>}/>
                    <Route path="/admin" exact render={()=> <Admin/>}/>
                </Switch>
            </BrowserRouter>
        );
    }
}

export default Router;

          但是路由在home和admin之间切换的时候,依然是重新渲染了2个子路由组件,
在这里插入图片描述
         查询相关资料后,发现排名靠前的一个 stackoverflow 上的相关问题。为了方便查看,就直接截图翻译了,(本博客与谷歌翻译达成深度合作):
在这里插入图片描述
          这段话,似乎 和我yy的 路由缓存是 相同的意思,但是demo code 表示render 渲染方式的确不是路由缓存
          再结合,这篇问题中提及最多的react-router 关于2种渲染方式的源码:

if (component)
  return match ? React.createElement(component, props) : null

if (render)
  return match ? render(props) : null

          和render 组件的生命周期来看:
在这里插入图片描述
render渲染范式 的确和demo code展示的效果一样,是重新挂载了 子路由组件。即不是路由缓存

3, 问题解决

  1. 回头,查看本文截图的那段官网文档翻译,
    在这里插入图片描述
    整体意思是 如果使用component 方式 ,通过 内联函数 ,则会导致子路由的重新渲染

         同时感谢腾讯云老铁–提供的博文一篇,根据这篇文章提供的代码:

import React,{Component} from 'react';
import { BrowserRouter,HashRouter , Route , Switch , Link} from 'react-router-dom';
 
class Bar extends React.Component {
    componentDidMount() {
        console.log("componentDidMount")
    }
    render() {
        const {idx} = this.props;
        return (
            <div>in Bar : {idx}</div>
        )
    }
}

class Router extends Component{
    constructor(prop) {
        super(prop);
        this.state = {idx: 1}
    }

    handleClick = () => {
        this.setState(state => ({idx: state.idx + 1}))
    };
    render() {
        return (
            <div>
                <div>
                    {this.state.idx}
                    <button onClick={this.handleClick}>add</button>
                </div>
                <div>
                    <BrowserRouter>
                        <Route component={() => (<Bar idx={this.state.idx}/>)}/>
                    </BrowserRouter>
                </div>
            </div>
        );
    }
}

export default Router;

每次点击按钮,都会重新走组件的render 方法,即使用component 内联方式传递参数的情况下,参数的变化会导致 子路由组件 被多次挂载卸载
在这里插入图片描述
而换成render 渲染方式向 子路由组件传递参数,参数改变的时候则不会重复渲染子组件
在这里插入图片描述
在这里插入图片描述

4, 总结


2种路由组件渲染方式的不同:
① 单纯的渲染组件的使用 component 方式
② 需要向渲染的子组件传递参数,或在选择子组件的时候增加一些逻辑(即使有回调函数)。则推荐使用render方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值