父组件 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 也跟着刷新了
1
doublelam 2020-06-09 18:41:58 +08:00 via Android
不要用匿名函数,重新创建一个子组件,用 react.memo 试试?
|
2
devwolf OP @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 依旧在父组件切换身份而触发重渲染时疯狂刷新 |
3
devwolf OP 这次的尝试曾使我一度怀疑是在父组件 componentDidMount 部署浏览器窗口的尺寸的监听与更新 screenHeight 所导致的(虽然没什么道理,只是在使用了 memo+useState 后比较是否有什么不同时发现——改变浏览器窗口尺寸也会触发 iframe 中内容的刷新,但是在父子组件两处都注释了这个监听器后改变尺寸刷新依旧。this.props.children 看起来同时也规避了这处问题)
|
4
ccraohng 2020-06-10 08:47:13 +08:00 via Android
错别字看着头疼。你看下那个二级路由循环那里是不是有改变什么
|
5
devwolf OP @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) ``` |
6
devwolf OP 上面 render 有些变量没来得及删,这是个上面安排得给别人擦屁股得项目,看上去上一位为了规避一些 bug 同样使用了一些怪招。笔者修改前,这儿得二级路由还是在用户点击菜单传值时才配置路由,现在采用得法子是登陆后全都配置好(有点好奇。。。笔者觉得这个才是正常思维来着)
|
7
ccraohng 2020-06-10 09:45:02 +08:00 via Android
可以试试,把箭头函数改成常量值,你可以看下 MsinFrame 是不是在不断加载卸载
|
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 一直在刷新」的问题了 |