【问题标题】:React JSX: is it normal that re-render of parent component remounts child component?React JSX:重新渲染父组件重新安装子组件是否正常?
【发布时间】:2018-01-19 21:14:01
【问题描述】:

在我的 React 应用程序的根组件中,我有这个:

class App extends Component {
...
  ComponentDidMount() {
    window.addEventListener('resize', this.handleResize, false);
  }
  handleResize{
    this.parentSize = {height: window.innerWidht - this.node.offsetLeft ..., width: ...};
    this.forceUpdate();
  }
  render() {
    <div ref="e=>this.node=e}>
      <ChildComponent parentSize={this.ParentSize} />
    </div>
  }
}

我注意到,当 App 组件通过 setState 或 forceUpdate() 重新渲染时,子组件实际上会重新挂载(因此每次更新都会调用 componentWillUnmount、componentWillMount、componentDidMount)。我期望的行为是再次调用 Child 组件的渲染函数。我最近升级到了 React-router 4.x,所以不确定是否与此有关。

谁能告诉我这是否是设计使然?当我尝试在其中获取数据时,多次调用我的 componentDidMount 会导致一些问题,并且我不想在调整大小期间一次又一次地执行该昂贵的操作。

更新:

我已找到此问题的可能原因。我有多个嵌套组件,并且由于很难发布整个项目,因此有时很难发布导致问题的实际代码。但我认为就是这样:

return (
  <div className="app-view" style={style} ref={el=>this.node=el}>
    <Switch>
      <Route exact path='/' component={() => <Home store={store} />} />
      <Route path='*' component={Error404} />
    </Switch>
  </div>
);

在这里我试图将道具传递给路由中的组件(React-router 4.x) 我通过提供一个创建主页的函数来做到这一点,该函数可能会在每次渲染时重新创建主页。

那么问题就变成了,如何在路由内每次渲染时不重新创建页面的情况下传递道具?

【问题讨论】:

  • 您可以添加您的 ChildComponent 代码吗?除非您导航,否则它不应多次调用 componentDidMount。
  • 可能的罪魁祸首是孩子正在接收一组更新的道具或状态,这会引发重新渲染。请分享您的子组件。
  • 查看更新:() => 路线内部导致了我认为的问题。子组件代码被替换为一个虚拟对象,除了将生命周期方法记录到控制台以调试问题外,它什么都不做。所以问题出在父组件中,我相信它在我问题的更新部分。

标签: reactjs resize react-router jsx rerender


【解决方案1】:

我已确认该问题与我最近的 React-Router 4.x 升级有关。 React-Router 的文档:

当你使用组件(而不是渲染或子组件,如下)时,路由器使用 React.createElement 从给定组件创建一个新的 React 元素。这意味着如果您为组件属性提供内联函数,您将在每次渲染时创建一个新组件。这会导致现有组件卸载和新组件安装,而不是仅更新现有组件。使用内联函数进行内联渲染时,请使用 render 或 children 道具(如下)。

感谢大家的支持。

【讨论】:

    【解决方案2】:

    在我看来,从您发布的代码来看,您提到的函数都改变了this.parentSize,然后重新呈现了页面。如果this.parentSize 的值没有改变,则它的值被重新赋值:

    this.parentSize = {height: window.innerWidht - this.node.offsetLeft ..., width: ...};
    

    如果我的理解是正确的,那么子组件需要重新渲染,因为用于生成组件的信息发生了变化,因此必须重新渲染组件以解决props的变化。很可能是 DOM 没有变化,所以页面在视觉上没有变化。

    您可以通过使用 Perf 插件和使用 printOperations 函数来检查正在执行的操作。

    防止重新渲染的一种方法是使用 shouldcomponentupdate 并在您不希望组件重新渲染时返回 false

    编辑:

    根据上面提供的信息,您似乎想通过调用父组件上的函数来更新子组件,但不希望父组件重新渲染?

    如果是这种情况,您可以执行以下操作:

    子组件第一次渲染时,调用componentWillMount,从父组件获取你想要能够控制的prop,并保存为状态,像这样:

    componentWillMount() {
      const { myProp } = this.props;
      this.setState({
        myProp
      });
    }
    

    然后在这个组件中创建一个函数,称为:

    updateMyProp(newProp) {
      this.setState({
        myProp: newProp
      })
    }
    

    从那时起,这个变量由state控制,而不是props

    接下来,在父页面上,组件需要有一个ref变量,像这样:

    <Yourcomponent
      ref={d=> this.componentName = d}
      ...
    />
    

    现在,您可以通过执行以下操作从父页面调用updateMyProp 函数:

    this.componentName.updateMyProp(someNewValue)
    

    这将导致子组件渲染,而不是父组件

    希望我能正确理解你的问题!!

    【讨论】:

    • 查看更新:() => 路线内部导致了我认为的问题。
    猜你喜欢
    • 2018-10-07
    • 2018-08-12
    • 2019-06-01
    • 2019-02-26
    • 1970-01-01
    • 2019-01-31
    • 1970-01-01
    • 2020-02-13
    • 2020-05-01
    相关资源
    最近更新 更多