防止组件在布线时取消安装
Prevent Component from Unmouting when Routing
我有一个子组件,当路由远离父组件时我需要保留它。
在网络上搜索,大多数答案都是关于 "react-router",但我使用的是 "react-router-dom"(又名 React Router V4)。
我对反应还很陌生,我认为这应该很简单,比如将组件标记为不被卸载或类似的东西。
import Home from "./home/Home";
import Top from "./top/Top";
export default class Layout extends React.Component{
render(){
return(
<Router>
<div class="wrp">
<Menu/>
<section class="left">
<Header/>
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/top" component={Top} />
</Switch>
<Footer/>
</section>
</div>
</Router>
);
}
}
在 "Home" 组件中有一个子组件需要保留在 DOM 中。
根据要求 Home 和 child 组件代码:
import React from "react";
import Sponsor from "./Sponsor";
import Feature from "./Feature";
import Top from "./Top";
import Discord from "./Discord";
import Middle from "./Middle";
export default class Home extends React.Component{
render(){
return(
<section class="main_wrp">
<Sponsor/>
<div class="bulk">
<Feature/>
<div class="co6">
<Top/>
<Discord/>
</div>
<Middle/>
</div>
</section>
);
}
}
子组件(Discord):
import React from "react";
export default class Discord extends React.Component{
render(){
return(
<div class="DiscordViewer">
<embed height='500px'src='https://somelink.com' />
</div>
);
}
}
一种可行的方法是将 <Discord\>
组件移出主页。
因此在布局中,您创建 <Discord\>
组件并将其作为子组件传递给所有其他组件。
布局
export default class Layout extends React.Component{
render(){
let discord = <Discord/>;
return(
<Router>
<div class="wrp">
<Menu/>
<section class="left">
<Header/>
<Switch>
<Route exact path="/" render={()=><Home>{discord}</Home>} />
<Route exact path="/top" render={()=><Top>{discord}</Top>} />
</Switch>
<Footer/>
</section>
</div>
</Router>
);
}
}
你的 Home 组件会变成
export default class Home extends React.Component{
render(){
return(
<section class="main_wrp">
<Sponsor/>
<div class="bulk">
<Feature/>
<div class="co6">
<Top/>
{this.props.children}
</div>
<Middle/>
</div>
</section>
);
}
}
您还可以将 <Discord/>
组件作为命名道具传递给所有需要显示它的组件,而不是将其作为子组件传递。
在不修改组件树的情况下,在离开其父节点导航后保留叶节点组件(本例中为 Discord)将违反树的定义。您不能简单地使用 CSS 隐藏和重新定位组件,您必须对从最近的父节点到该叶节点的树的整个分支执行此操作。这可能会导致不必要的复杂性和性能不佳,尽管它可以像这样执行:
const HomeWrapper = withRouter(props => (
<div style={props.location.pathname !== '/' ? {display: 'none'} : {}}>
<Home {...props} />
<div>
))
<HomeWrapper />
<Switch>
<Route exact path="/top" component={Top} />
<Route exact path="/other" component={OtherComponent} />
</Switch>
如果您的组件结构灵活,您可以将 Discord 组件从主路由移到隐藏的 div。然后,您将使用非反应 DOM 操作在外部隐藏 div 和主页中显示的 div 之间移动不和谐。在您的 Home 组件中,您可以呈现如下所示的 DiscordWrapper 组件。您需要从 shouldComponentUpdate return false 来阻止更新。 :
<div id='discord-wrapper-external' style={{display: 'none'}}>
<Discord id='discord-dom-node'/>
</div>
class DiscordWrapper extends React.Component {
componentDidMount() {
this.el = document.getElementById('discord-dom-node')
document.getElementById('discord-wrapper-internal').appendChild(this.el)
}
shouldComponentUpdate() {
return false
}
componentWillUnmount() {
document.getElementById('discord-wrapper-external').appendChild(this.el)
}
render() {
return <div id='discord-wrapper-internal' />
}
我有一个子组件,当路由远离父组件时我需要保留它。 在网络上搜索,大多数答案都是关于 "react-router",但我使用的是 "react-router-dom"(又名 React Router V4)。 我对反应还很陌生,我认为这应该很简单,比如将组件标记为不被卸载或类似的东西。
import Home from "./home/Home";
import Top from "./top/Top";
export default class Layout extends React.Component{
render(){
return(
<Router>
<div class="wrp">
<Menu/>
<section class="left">
<Header/>
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/top" component={Top} />
</Switch>
<Footer/>
</section>
</div>
</Router>
);
}
}
在 "Home" 组件中有一个子组件需要保留在 DOM 中。
根据要求 Home 和 child 组件代码:
import React from "react";
import Sponsor from "./Sponsor";
import Feature from "./Feature";
import Top from "./Top";
import Discord from "./Discord";
import Middle from "./Middle";
export default class Home extends React.Component{
render(){
return(
<section class="main_wrp">
<Sponsor/>
<div class="bulk">
<Feature/>
<div class="co6">
<Top/>
<Discord/>
</div>
<Middle/>
</div>
</section>
);
}
}
子组件(Discord):
import React from "react";
export default class Discord extends React.Component{
render(){
return(
<div class="DiscordViewer">
<embed height='500px'src='https://somelink.com' />
</div>
);
}
}
一种可行的方法是将 <Discord\>
组件移出主页。
因此在布局中,您创建 <Discord\>
组件并将其作为子组件传递给所有其他组件。
布局
export default class Layout extends React.Component{
render(){
let discord = <Discord/>;
return(
<Router>
<div class="wrp">
<Menu/>
<section class="left">
<Header/>
<Switch>
<Route exact path="/" render={()=><Home>{discord}</Home>} />
<Route exact path="/top" render={()=><Top>{discord}</Top>} />
</Switch>
<Footer/>
</section>
</div>
</Router>
);
}
}
你的 Home 组件会变成
export default class Home extends React.Component{
render(){
return(
<section class="main_wrp">
<Sponsor/>
<div class="bulk">
<Feature/>
<div class="co6">
<Top/>
{this.props.children}
</div>
<Middle/>
</div>
</section>
);
}
}
您还可以将 <Discord/>
组件作为命名道具传递给所有需要显示它的组件,而不是将其作为子组件传递。
在不修改组件树的情况下,在离开其父节点导航后保留叶节点组件(本例中为 Discord)将违反树的定义。您不能简单地使用 CSS 隐藏和重新定位组件,您必须对从最近的父节点到该叶节点的树的整个分支执行此操作。这可能会导致不必要的复杂性和性能不佳,尽管它可以像这样执行:
const HomeWrapper = withRouter(props => (
<div style={props.location.pathname !== '/' ? {display: 'none'} : {}}>
<Home {...props} />
<div>
))
<HomeWrapper />
<Switch>
<Route exact path="/top" component={Top} />
<Route exact path="/other" component={OtherComponent} />
</Switch>
如果您的组件结构灵活,您可以将 Discord 组件从主路由移到隐藏的 div。然后,您将使用非反应 DOM 操作在外部隐藏 div 和主页中显示的 div 之间移动不和谐。在您的 Home 组件中,您可以呈现如下所示的 DiscordWrapper 组件。您需要从 shouldComponentUpdate return false 来阻止更新。 :
<div id='discord-wrapper-external' style={{display: 'none'}}>
<Discord id='discord-dom-node'/>
</div>
class DiscordWrapper extends React.Component {
componentDidMount() {
this.el = document.getElementById('discord-dom-node')
document.getElementById('discord-wrapper-internal').appendChild(this.el)
}
shouldComponentUpdate() {
return false
}
componentWillUnmount() {
document.getElementById('discord-wrapper-external').appendChild(this.el)
}
render() {
return <div id='discord-wrapper-internal' />
}