componentDidMount()没有被调用,但仅在特定情况下被调用

时间:2018-06-13 00:47:12

标签: javascript reactjs react-router react-router-v4 react-router-dom

只是抬头:这是一个非常奇怪的问题。我会尽力清楚地解释这个问题。这种情况发生在使用ReactJs的{​​{1}}应用中。

我有一些组件需要来自URL的某种类型的参数。我也有不依赖参数的组件。

如果我选择需要任何参数的组件,则无任何问题。

所以,我转到React Router,然后Home,这两个都不需要任何参数,我可以随心所欲地来回走动,没有问题。

但是,如果我转到使用参数的组件,然后尝试使用另一个使用参数的组件,那么我会收到错误。该错误表明组件Account List应该加载未正确安装,这会引发错误,告诉我子组件所需的数据丢失。我得到的错误非常简单。他们只是简单地说:

  

this.props.something是必需的,但未定义

这是react-router中的路线:

App.jsx

正如您从路线中看到的那样,import React, { Component } from 'react'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import { Route, Switch, withRouter } from 'react-router-dom'; // Import components here // Just showing one for brevity import Home from '../components/home/Home'; import * as appActions from '../actions/app-actions'; class App extends Component { constructor(props) { super(props); } render() { return( <div> <Switch> <Route exact path="/member" component={Home} /> <Route exact path="/member/accounts" component={Accounts} /> <Route exact path="/member/projects" component={ProjectsList} /> <Route path="/member/projects/profile/:id" component={ProjectProfile} />| <Route exact path="/member/tasks" component={TasksList} /> <Route path="/member/tasks/profile/:id" component={TaskProfile} /> </Switch> </div> ); } } function mapStateToProps(state) { return { member: state.member.memberData } } function mapDispatchToProps(dispatch) { return { actions: bindActionCreators(appActions, dispatch) }; } export default withRouter(connect(mapStateToProps, mapDispatchToProps)(App)); ProjectProfile组件都需要ID。此外,TaskProfileProjectProfile组件都是相当简单的父组件,可以完成两件事:

  1. 进行API调用以在TaskProfile事件
  2. 中加载数据
  3. 他们还会根据用户的屏幕分辨率加载正确的子组件
  4. 这是我的componentDidMount()组件,而ProjectProfile与此完全相同。

    TaskProfile

    关于这一点最奇怪的部分是,如果我继续在import React, { Component } from 'react' import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; // Actions import * as projectProfileActions from '../../../actions/project-profile-actions'; // Components import Desktop from './ProjectProfileDesktop'; import Mobile from './ProjectProfileMobile'; class ProjectProfile extends Component { constructor(props) { super(props); }; componentDidMount() { const id = this.props.match.params.id; this.props.actions.getData(id); } render() { return ( <div className="height-100 width-100"> <div className="height-100 width-100 row row-clean"> {this.props.ui.isDesktop || this.props.ui.isTablet ? <Desktop /> : this.props.ui.isMobile ? <Mobile /> : null} </div> </div> ); } } function mapStateToProps(state) { return { ui: state.app.window }; } function mapDispatchToProps(dispatch) { return { actions: bindActionCreators(projectProfileActions, dispatch) }; } export default connect(mapStateToProps, mapDispatchToProps)(ProjectProfile); 和任何其他组件之间往返,并远离ProjectProfile,则没有问题。我甚至可以使用不同的ID来点击TaskProfile,一切正常。只有当我使用参数转到另一个组件时,它才会失败。我可以对ProjectProfile做同样的事情。我可以继续使用不同的ID来TaskProfile,或者在TaskProfile和任何组件之间来回切换,不带参数,一切正常。

    只有当我首先转到TaskProfile,然后尝试转到ProjectProfile或反之,发生错误。

    错误只是告诉我TaskProfile所需的数据不存在。

    进一步检查显示,在使用参数加载组件后,如果我使用参数转到另一个组件,我只是没有按下第二个组件中的ProjectProfileDesktop方法。看起来componentDidMount()方法中的某些内容会导致问题并阻止其转到render()。我不确定问题是什么,因为我没有收到任何错误。我在componentDidMount()方法的顶部放置了debugger。虽然我没有看到确切的错误,但流程告诉我某些事情肯定是错误的。

    另请注意我使用render()。我已经看到了涉及withRouter的一些问题但是,到目前为止,我还找不到具体的内容。

    我还想提一下,我也有条带提供程序包装我的withRouter组件。不确定这是否也在这个问题中发挥作用。这是我Apprender()的样子:

    index.js

    我很欣赏这方面的一些指示。

    更新

    我观察到的一个行为是,在使用param加载组件后,当我用param命中第二个组件时,我在第一个render( <Provider store={store}> <BrowserRouter history={browserHistory}> <StripeProvider apiKey="my_key"> <App /> </StripeProvider> </BrowserRouter> </Provider>, document.getElementById('root') ); 方法之后第一个render()方法点击createElement方法。 },代码跳转到ReactInstrumentation.debugTool.onBeginLifeCycleTimer - 请参见下面的屏幕截图。

    enter image description here

    更新2:

    此时,我确信问题不是由react-router引起的,因为我将所需的ID硬编码到组件中,这样我就不依赖于{{1}或其他任何东西得到它。

    我还从react-router/:id组件的路线中删除了TaskProfile参数。

    我仍然有同样的行为。因此,有些东西阻止了ProjectProfile方法被调用。我还尝试componentDidMount()来查看它是否被调用而不是。我将componentDidUpdate()放在两个组件中,当我在应用程序的其他位置导航时,在两个组件componentWillUnmount()中都会被调用,因此可以认为两个组件都已卸载正常。

    所以底线是componentWillUnmount()方法中的某些内容阻止调用render()或任何其他生命周期方法,但这只发生在这种特殊情况下。

    我现在感谢任何建议!!!

2 个答案:

答案 0 :(得分:6)

已经有一个多星期了,我一直在这个问题上犹豫不决,终于解决了。诚然,我认为我理解的许多概念在此过程中变得更加清晰。

该错误是由于我处理“ isLoading”动画逻辑的逻辑错误-是的,那样简单又愚蠢!

我真正想在这里分享的是我为以后可能会遇到类似行为的每个人吸取的教训。

  1. 每次加载组件时,您应该点击componentDidMount()。即使您来回加载相同的组件。但是只有首先卸载组件后,您才打componentDidMount()。如果未卸下该组件,则在以后使用该组件时不会碰到componentDidMount()。因此,请仔细查看您的逻辑,以了解如果您离开组件,则是否已卸载组件。我认为,查看是否正在发生的最简单方法是在其中添加componentWillUnmount()的{​​{1}}方法。如果您在离开组件时单击此方法,则表示它正在卸载。
  2. 在此过程中进行了大量研究,以了解在哪里进行API调用以获取数据的最佳位置,并且显然debugger仍然是进行此操作的最佳位置。话虽如此,您可能需要在componentDidMount()中添加其他逻辑来确保您不会进行任何不必要的API调用,因为您的数据可能仍在商店中。
  3. 在研究期间,有人建议最好使用componentDidMount()方法来进行API调用以获取数据。这是不好的建议!实际上,componentWillReceiveProps()componentWillReceiveProps()componentWillUpdate()方法已被弃用,因此我们不应出于两个原因使用它们:将来的兼容性和遵循最佳实践。以下是有关为何不推荐使用它们的更多信息:https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html
  4. 也许最重要的一课是:问题的原因可能比您想象的要简单得多-通常是-代码中的逻辑可能是问题的原因-通常是! / li>

希望这些课程将帮助其他人快速而轻松地找到解决方案!

答案 1 :(得分:-3)

ComponentDidMount只在安装组件时调用一次。当你使用prop然后进行api调用时,我会使用componentWillReceiveProps并检查道具,然后进行api调用。

如果你想检查你的流是否使用了componentDidMount,请使用console.log进行检查。

问候!