父组件 state 更新触发渲染导致子组件中 iframe 也跟着刷新,疑惑自己误打误撞的“解决?”办法 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
devwolf
V2EX    React

父组件 state 更新触发渲染导致子组件中 iframe 也跟着刷新,疑惑自己误打误撞的“解决?”办法

  •  
  •   devwolf
    yctjb1 2020-06-09 16:59:33 +08:00 2485 次点击
    这是一个创建于 1956 天前的主题,其中的信息可能已经有所发展或是发生改变。

    父组件 state 更新触发渲染导致子组件中 iframe 也跟着刷新,莫名通过“原本子组件部署在父组件 render 中得 return 处,现将该处替换为 this.props.children,然后子组件对应部署在父组件得部署区得双标签内”来规避了

    前半句 [父组件 state 更新触发渲染导致子组件中 iframe 也跟着刷新] 不知各位是否有遇见,
    后半句是笔者误打误撞试错出来得“解决?”办法,至少规避了父组件重新渲染时子组件 iframe 一直在刷新.

    这会儿想探究一下其中得原因,不知从何入手。
    当然如果笔者对现象分析错误“实际上压根没有上述这回事,导致该效果得实际原因是别的什么”
    还请 v 佬们告知。

    业务逻辑以及项目结构得话大概描述一下

     <Router basename="/" hashType="hashbang"> <Switch> <Route path="/main" compOnent={()=><LayoutContainer> <ChildRoute/></LayoutContainer>}/> </Switch> </Router> //LayoutContainer 里是一堆布局,挑个合适得地方塞上{this.props.children} 

    然后 ChildRoute 里就是二级路由以及 iframe 的配置

    <Route exact path={'/main/'+item.part} key={item.all} compOnent={()=><iframe name="mainFrame" style={{width: '100%', height: screenHeight, border:'0px'}} OnLoad={()=>this.setState({loading:false})} sandbox="allow-same-origin allow-scripts allow-forms allow-top-navigation allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-presentation" src ={fullsrc}></iframe>/>}/> 

    流程就是,点击布局页面切换了登陆用户得身份会更新 state 导致 LayoutContainer 重新渲染,若不采用 this.props.children 得法子将导致其“子组件”得 iframe 也跟着刷新了

    9 条回复    2020-06-10 13:54:01 +08:00
    doublelam
        1
    doublelam  
       2020-06-09 18:41:58 +08:00 via Android
    不要用匿名函数,重新创建一个子组件,用 react.memo 试试?
    devwolf
        2
    devwolf  
    OP
       2020-06-10 08:24:19 +08:00
    @doublelam

    ```
    import React, {Component ,Fragment,useState} from "react";

    import {Spin} from 'antd';

    const MainFrame = React.memo(props => {



    const [loading, updateLoading] = useState(true);
    const [screenHeight, updateScreenHeight] = useState(document.documentElement.clientHeight-70-64);



    //这里获取的高度为 iframe 服务
    //window.addEventListener("resize",()=>{
    // const screenHeight = document.documentElement.clientHeight;
    // updateScreenHeight(screenHeight-70-64)
    //});//获得窗口高度




    const fullsrc = props.fullsrc

    return (<Fragment>
    <Spin tip= "加载中请稍后..." spinning={loading}>
    <iframe name="mainFrame"
    style={{width: '100%',
    height: screenHeight,
    border:'0px'}}
    OnLoad={()=>updateLoading(false)}
    sandbox="allow-same-origin allow-scripts allow-forms allow-top-navigation
    allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-popups-to-escape-sandbox
    allow-presentation"
    // scrolling="auto"
    src ={fullsrc}></iframe>
    </Spin>

    </Fragment>)

    });

    export default MainFrame;
    ```
    我尝试使用了 memo + useState,看起来 iframe 依旧在父组件切换身份而触发重渲染时疯狂刷新
    devwolf
        3
    devwolf  
    OP
       2020-06-10 08:43:02 +08:00
    这次的尝试曾使我一度怀疑是在父组件 componentDidMount 部署浏览器窗口的尺寸的监听与更新 screenHeight 所导致的(虽然没什么道理,只是在使用了 memo+useState 后比较是否有什么不同时发现改变浏览器窗口尺寸也会触发 iframe 中内容的刷新,但是在父子组件两处都注释了这个监听器后改变尺寸刷新依旧。this.props.children 看起来同时也规避了这处问题)
    ccraohng
        4
    ccraohng  
       2020-06-10 08:47:13 +08:00 via Android
    错别字看着头疼。你看下那个二级路由循环那里是不是有改变什么
    devwolf
        5
    devwolf  
    OP
       2020-06-10 09:13:32 +08:00
    @ccraohng

    那儿也就一个配置路由的操作来着
    ```
    import React,{Component} from "react";
    import {Switch,Route,Redirect,withRouter} from 'mirrorx';

    import HomeContainer from "Pages/Home/HomeContainer"
    import PerconContainer from "Pages/Person/personContainer"
    import MainFrame from "./MainFrame"

    class ChildRoute extends Component{
    constructor(props){
    super(props);

    this.state={
    pathname_list:[]
    }
    }
    componentWillMount(){

    let pathname_list = JSON.parse(sessionStorage.getItem("url_routes"));
    if(pathname_list){
    // console.log("有了有了")
    this.setState({pathname_list})
    }else{
    // console.log("我没有")
    }



    }

    render(){
    const redirectUrl = JSON.parse(sessionStorage.getItem("url"));
    const userInfo = sessionStorage.getItem("userInfo");
    const user = sessionStorage.getItem("user");
    const url = "/main/"+redirectUrl;
    const {match} = this.props;
    const token = sessionStorage.getItem("TOKEN");
    const src = redirectUrl+"?user="+user+"&token="+token;



    return(
    token==null?(
    <Redirect to="/login"/>
    ) :
    (
    <Switch>
    <Route exact path={'/main'} compOnent={HomeContainer} breadcrumbName="首页" />
    <Route exact path={'/main/person'} compOnent={PerconContainer} />

    {this.state.pathname_list.length!==0&&this.state.pathname_list.map(item=>
    <Route exact path={'/main/'+item.part} key={item.all} compOnent={()=><MainFrame fullsrc={item.all+"?user="+user+"&token="+token}/>}/>
    )}

    </Switch>
    )
    )
    }
    }
    export default withRouter(ChildRoute)

    ```
    devwolf
        6
    devwolf  
    OP
       2020-06-10 09:18:26 +08:00
    上面 render 有些变量没来得及删,这是个上面安排得给别人擦屁股得项目,看上去上一位为了规避一些 bug 同样使用了一些怪招。笔者修改前,这儿得二级路由还是在用户点击菜单传值时才配置路由,现在采用得法子是登陆后全都配置好(有点好奇。。。笔者觉得这个才是正常思维来着)
    ccraohng
        7
    ccraohng  
       2020-06-10 09:45:02 +08:00 via Android
    可以试试,把箭头函数改成常量值,你可以看下 MsinFrame 是不是在不断加载卸载
    feichao
        8
    feichao  
       2020-06-10 13:11:12 +08:00   1

    ```
    <Route exact path={...} key={item.all} compOnent={()=><iframe ......
    ```

    改成

    ```
    <Route exact path={...} key={item.all} render={()=><iframe ......
    ```

    试下,应该就能避免「父组件重新渲染时子组件 iframe 一直在刷新」的问题了
    devwolf
        9
    devwolf  
    OP
       2020-06-10 13:54:01 +08:00 via Android
    @feichao 非常感谢,render 确实能解决这个问题。
    orz 顺着这个方向我查查去
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2770 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 23ms UTC 07:06 PVG 15:06 LAX 00:06 JFK 03:06
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86