【问题标题】:React Component Mounting TwiceReact 组件安装两次
【发布时间】:2018-03-01 17:11:14
【问题描述】:

在我的 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>
    )
  }
}

为了减少打字,我决定将组件包装在一个高阶组件中,它的 目的是调度一个动作,该动作将在顶级 Exhibit 父组件上设置正确的背景图像。

这是高阶组件:

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 的东西? 无论如何,对于为什么执行两次的任何帮助将不胜感激。

【问题讨论】:

    标签: reactjs redux react-router


    【解决方案1】:

    问题是这里的component prop 是一个函数应用程序,它在每次渲染时产生一个新类。这将导致前一个组件卸载并安装新组件(有关更多信息,请参阅the docs for react-router)。通常你会使用 render 属性来处理这个问题,但这不适用于高阶组件,因为在渲染期间使用 HOC 应用程序创建的任何组件都将在 React 的协调期间重新安装。

    一个简单的解决方案是在 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} 而不是参数&lt;ComposedComponent/&gt; 的普通组件,并将组件包装在每个Route 中:

    <Route path={`${match.url}/wall-one`}
           render={(props) => <Wrap><WallOne {...props}/></Wrap>}
    />
    

    请注意,您需要使用 render 而不是 component 来防止重新安装。如果组件不使用路由道具,你甚至可以删除{...props}

    【讨论】:

    • 现在将其中的一些代码输入我的文本编辑器。很快就会回复>_
    • 太棒了!在这里为我节省了很多痛苦。现在你解释说它在每次渲染时都会产生一个新类,这很有意义。
    • 乐于助人 :-)
    • 很高兴看到这仍然对今天的人们有所帮助。很好的答案@Oblosys!
    【解决方案2】:

    在 2020 年,这是由 &lt;React.StrictMode&gt; 组件引起的,该组件在 Create React App 的新版本中包裹在 &lt;App /&gt; 周围。从index.js 中删除有问题的组件修复了我所有组件的双重安装问题。我不知道这是设计使然还是什么,但是每次都看到 console.logs() 两次是令人讨厌和误导的。

    【讨论】:

    • 好收获。我以前没有注意到这一点。可以提交错误报告吗?
    • 太棒了!省了我几个小时挠头的时间!对我来说 StrictMode 会以这种方式运行是有道理的,所以我怀疑它可能被认为是一个错误。然而,双重安装是如此出乎意料,尤其是当您不知道&lt;React.StrictMode&gt; 甚至在那里时......在控制台中看到指示正在发生的事情的输出可能会很好。
    • 我花了一整天的时间调试我的应用程序,以为我做错了什么。这修复了它(反应版本 17.0.2)npm。谢谢。
    【解决方案3】:

    如果您使用“Hidden Material UI React”,它会在您每次调用它时安装您的组件。比如我写了下面这样一个:

    <Hidden mdDown implementation="css">
        <Container component="main" maxWidth="sm">
            {content}
        </Container>
    </Hidden>
    <Hidden smUp implementation="css">
        {content}
    </Hidden>
    

    它调用两个隐藏组件中的两个内容。花了我很多时间。

    【讨论】:

      猜你喜欢
      • 2020-09-30
      • 2019-05-26
      • 2022-01-16
      • 1970-01-01
      • 1970-01-01
      • 2017-12-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多