javascript - componentDidMount()不会被调用,而只会在特定情况下被调用

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

请注意:这是一个非常奇怪的问题。我会尽力清楚地解释这个问题。这是在我的ReactJs应用程序中使用React Router发生的。

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

如果我转到而不是需要任何参数的组件,则没有任何问题。

因此,我先转到Home,然后转到Account List,这两个参数都不需要任何参数,我可以根据需要来回多次,没有问题。

但是,如果我转到使用参数的组件,然后尝试转到另一个使用参数的组件,则会收到错误消息。该错误表明应该正确加载组件react-router并没有正确安装,这引发了一个错误,告诉我子组件所需的数据丢失。我遇到的错误非常简单。他们只是说:

this.props.something is required but undefined



这是我在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));

从路由中可以看到,ProjectProfileTaskProfile组件都需要ID。此外,ProjectProfileTaskProfile组件都是相当简单的父组件,它们执行以下两项操作:
  • 进行API调用以在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和任何其他组件之间来回移动,并且远离TaskProfile,则不会有问题。我什至可以用不同的ID命中ProjectProfile,并且一切正常。仅当我使用参数转到另一个组件时,所有操作均会失败。我可以使用TaskProfile做同样的事情。我可以用不同的ID继续打TaskProfile,或者在TaskProfile和任何组件之间来回切换,而无需使用一个参数,一切正常。

    仅当我先进入ProjectProfile,然后再尝试去TaskProfile或反之亦然时,才会发生错误。

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

    进一步的检查显示,在向一个带有参数的组件加载后,如果我转到另一个带有参数的组件,那么我不会碰到第二个组件中的componentDidMount()方法。看来render()方法中的某些问题导致了问题,并阻止了它进入componentDidMount()。我不确定是什么问题,因为我没有收到任何错误。我将debugger放在render()方法的顶部。尽管我没有看到确切的错误,但流程显示出确实有问题。

    另请注意,我正在使用withRouter。我已经看到一些涉及withRouter的问题,但是到目前为止,我仍然找不到任何具体的问题。

    我还想提到,我也有Stripe提供程序包装了App组件。不知道这是否也在此问题中起作用。这是render()在我的index.js中的样子:
    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硬编码到组件中,因此我不依赖react-router或其他任何东西来获取它。

    我还从/:idTaskProfile组件的路由中删除了ProjectProfile参数。

    我仍然得到相同的行为。因此,有些事情阻止了componentDidMount()方法的调用。我还尝试了componentDidUpdate()来查看它是否被调用,但不是。我在两个组件中都放置了componentWillUnmount(),当我在应用程序中的其他位置导航时,两个组件中都调用了componentWillUnmount(),因此人们可能会认为这两个组件都无法卸载。

    因此,最重要的是render()方法中的某些内容阻止了componentDidMount()或任何其他生命周期方法的调用,但这仅在这种特定情况下才发生。

    我很乐意在此提出任何建议!

    最佳答案

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

    该错误是由于我处理“isLoading”动画逻辑的逻辑错误所致-是的,如此简单而愚蠢!!!

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

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

  • 希望这些类(class)能帮助其他人迅速而轻松地找到解决方案!

    关于javascript - componentDidMount()不会被调用,而只会在特定情况下被调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50827695/

    相关文章:

    reactjs - React 路由器重定向页面但组件未呈现

    unit-testing - 使用 Link 测试 React Router

    javascript - 如果不等于值,如何遍历推送数组?

    javascript - emberjs 中查询参数允许的值

    javascript - Intl.DateTimeFormat 在节点和浏览器中以不同的方式工作

    reactjs - react 和 Redux : Uncaught Error: A state mutation was detected between dispatches

    javascript - react Redux : dispatch returning data to component

    reactjs - yarn 升级后 React 中的 Websocket 握手错误

    javascript - 如何在React Router中生成动态路由?

    javascript - 单击随机图像更改时按钮消失