在我的React / Redux / ReactRouterV4应用程序的一小部分内部,我有以下组件层次结构,
- Exhibit (Parent)
-- ExhibitOne
-- ExhibitTwo
-- ExhibitThree
在Exhibit的子女中,大约有6种不同的可能路线也可以呈现。别担心,我会用一些代码来解释。
这是我的父展览组件:
export class Exhibit extends Component {
render() {
const { match, backgroundImage } = this.props
return (
<div className="exhibit">
<Header />
<SecondaryHeader />
<div className="journey"
style={{
color: 'white',
backgroundImage: `url(${backgroundImage})`,
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat',
backgroundPosition: 'center-center'
}}>
<Switch>
<Route path={`${match.url}/exhibit-one`} component={ExhibitOne} />
<Route path={`${match.url}/exhibit-two`} component={ExhibitTwo} />
<Route path={`${match.url}/exhibit-three`} component={ExhibitThree} />
<Redirect to="/" />
</Switch>
</div>
</div>
)
}
}
基本上,它所做的就是展示其中一个展品子组件,并设置背景图片。
以下是其中一个子组件,ExhibitOne:
export default class ExhibitOne extends Component {
constructor(props) {
super(props)
}
render() {
const { match } = this.props
return (
<div className="exhibit-one">
<Switch>
<Route path={`${match.url}/wall-one`} component={ExhibitHOC(WallOne)} />
<Route path={`${match.url}/wall-two`} component={ExhibitHOC(WallTwo)} />
<Route path={`${match.url}/wall-three`} component={ExhibitHOC(WallThree)} />
<Route path={`${match.url}/wall-four`} component={ExhibitHOC(WallFour)} />
<Route path={`${match.url}/wall-five`} component={ExhibitHOC(WallFive)} />
<Route path={`${match.url}/wall-six`} component={ExhibitHOC(WallSix)} />
</Switch>
</div>
)
}
}
为了减少打字,我决定将组件包装在一个高阶组件中 目的是调度一个动作,在顶级展览父组件上设置正确的背景图像。
这是高阶组件:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import * as actions from '../../actions/wall-background-image'
export default function(ComposedComponent) {
class ExhibitHoc extends Component {
componentDidMount = () => this.props.setBackgroundImage(`./img/exhibit-one/${this.getWall()}/bg.jpg`)
getWall = () => {
// this part isnt important. it is a function that determines what wall I am on, in order to set
// the proper image.
}
render() {
return <ComposedComponent />
}
}
return connect(null, actions)(ExhibitHoc);
}
在初次加载ExhibitOne时,我可以看到setBackgroundImage动作创建者通过查看执行了两次 在Redux Logger的控制台中。我最初倾向于使用componentDidMount是因为我认为使用它 会限制动作创建者只执行一次。以下是日志的屏幕截图:
我想我可能误解了高阶组件的工作原理,或者是某种类型的React Router V4? 无论如何,任何帮助将非常感谢为什么这次执行两次。
答案 0 :(得分:9)
在2020年,这是由<React.StrictMode>
组件引起的,该组件在新版本的Create React App中包裹在<App />
周围。从index.js
中删除有问题的组件,从而解决了我所有组件的双重安装问题。我不知道这是设计使然还是什么原因,但是每次都看到console.logs()两次都是令人讨厌和误导的。
答案 1 :(得分:6)
问题是这里的component
道具是一个函数应用程序,它在每个渲染上产生一个新类。这将导致先前的组件卸载并挂载新组件(有关详细信息,请参阅the docs for react-router)。通常你会使用render
prop来处理这个问题,但这不适用于高阶组件,因为在渲染过程中使用HOC应用程序创建的任何组件都会在React&#39; s中重新安装。和解无论如何。
一个简单的解决方案是在ExhibitOne
类之外创建组件,例如:
const ExhibitWallOne = ExhibitHOC(WallOne);
const ExhibitWallTwo = ExhibitHOC(WallTwo);
..
export default class ExhibitOne extends Component {
..
<Route path={`${match.url}/wall-one`} component={ExhibitWallOne} />
<Route path={`${match.url}/wall-two`} component={ExhibitWallTwo} />
..
}
或者,根据包装器的作用,可以将其声明为呈现{this.props.children}
而不是参数<ComposedComponent/>
的普通组件,并将组件包装在每个Route
中。 }:
<Route path={`${match.url}/wall-one`}
render={(props) => <Wrap><WallOne {...props}/></Wrap>}
/>
请注意,您需要使用render
代替component
来阻止重新安装。如果组件不使用路由道具,您甚至可以删除{...props}
。
答案 2 :(得分:0)
如果您使用“隐藏的材料UI React”,则每次调用它都会安装您的组件。例如,我写了以下代码:
<Hidden mdDown implementation="css">
<Container component="main" maxWidth="sm">
{content}
</Container>
</Hidden>
<Hidden smUp implementation="css">
{content}
</Hidden>
它调用两个隐藏组件中的两个内容。花了我很多时间。