嵌套的React + Meteor组件在页面加载时不接收道具

时间:2017-07-21 17:07:10

标签: javascript reactjs meteor react-router

我有一个名为Profile的嵌套React组件。在整个页面上刷新所有数据都正确加载,但是当我单击链接将我带到另一个页面(如“设置”),然后导航回“配置文件”时,不会加载任何数据。我注意到在刷新时,componentWillReceiveProps会触发我的console.log,但是当我使用链接时它不会触发。我想知道这是否是由于我的createContainer没有正确卸载?

Profile receives props on full refresh and loads correctly. I navigate to settings and everything works correctly. I navigate back to profile and nothing loads, componentWillReceiveProps is not fired

图1:配置文件在完全刷新时收到道具并正确加载。 图2:我导航到设置,一切正常。 图3:我导航回配置文件并且没有任何加载,componentWillReceiveProps没有被触发

这些组件是使用react路由器的嵌套路由。但我很困惑如何设置工作正常,没有明显的代码差异。

非常感谢任何帮助,谢谢!

ProfileContainer.js

import React, { Component } from 'react';
import { Meteor } from 'meteor/meteor';
import { createContainer } from 'meteor/react-meteor-data';
import introJs from 'intro.js';
import { browserHistory } from 'react-router';
import '../../../../../node_modules/intro.js/introjs.css';

// Custom
import ProfileForm from './ProfileForm';
import { countryList, statesList, industryList, incomesList, monthsList, educationsList, ofAgeCheck } from '../../../../modules/helpers.js';
import { upsertUserProfile } from '../../../../../imports/api/methods/profile/settingsMethods';
import { changeIntroTour } from '../../../../api/methods/user/userMethods';

// Collections
import { UserProfile } from '../../../../api/collections/profile/userProfileCollection';
import { IntroTour } from '../../../../api/collections/user/introTourCollection';

const expertiseOptions = [];
const dayOptions = [];
const yearOptions = [];

const profileIntro = {
  text: 'Tell us a little about yourself.',
};
const tourObj = {
  userId: Meteor.userId(),
  page: 'profile',
};
class ProfileFormContainer extends Component {

  constructor() {
    super();
    const NA = 'N/A';
    this.state = {
      firstView: NA,
      birthmonth: NA,
      birthday: NA,
      birthyear: NA,
      sex: NA,
      expertise: '',
      country: '',
      state: '',
      industry: '',
      income: '',
      education: '',
      showTour: false,
      tourRunning: false,
    };
  }

  componentDidMount() {
    this.loadExpertiseOptions();
    this.loadBirthdateOptions();
    this.handleChange = this
      .handleChange
      .bind(this);
    this.upsertToDB = this
      .upsertToDB
      .bind(this);
  }

  componentWillUnmount() {
    introJs.introJs().exit();
  }

  componentWillReceiveProps(nextProps) {
    console.log(nextProps);
    this.existingSettings(nextProps);
    if (nextProps.intro.length > 0) {
      this.setState({
        showTour: nextProps.intro[0].profileTour,
      }, () => {
        if (!this.state.tourRunning) {
          this.runTour();
        }
      });
    }
  }

  runTour() {
    if (this.state.showTour === true) {
      this.setState({
        tourRunning: true,
      });
      introJs.introJs().setOption('doneLabel', 'Next').start().oncomplete(() => {
        changeIntroTour.call(tourObj);
        browserHistory.push('/user/settings');
      })
        .onexit(() => {
          changeIntroTour.call(tourObj);
        });
    }
  }

  handleChange(event) {
    this.setState({
      [event.target.name]: event.target.value,
    });
  }

  existingSettings(data) {
    const user = data.profile[0];
    this.setState({
      birthmonth: user.birthmonth,
      birthday: user.birthday,
      birthyear: user.birthyear,
      sex: user.sex,
      expertise: user.expertise,
      country: user.country,
      state: user.state,
      industry: user.industry,
      income: user.income,
      education: user.education,
    });
  }

  loadExpertiseOptions() {
    for (let i = 1; i <= 10; i++) {
      expertiseOptions.push(
        <option key={ i } value={ i }>
          { i }
        </option>
      );
    }
  }


  loadBirthdateOptions() {
    this.loadDayOptions();
    this.loadYearOptions();
  }

  loadDayOptions() {
    dayOptions.push(
      <option key={ ' ' } value={ ' ' }>
      </option>
    );
    for (let i = 1; i <= 31; i++) {
      dayOptions.push(
        <option key={ i } value={ i }>
          { i }
        </option>
      );
    }
  }

  loadYearOptions() {
    yearOptions.push(
      <option key={ ' ' } value={ ' ' }>
      </option>
    );
    for (let i = new Date().getFullYear(); i >= 1900; i--) {
      yearOptions.push(
        <option key={ i } value={ i }>
          { i }
        </option>
      );
    }
  }

  upsertToDB() {
    if (ofAgeCheck(13, this.state.birthmonth, this.state.birthday, this.state.birthyear)) {
      Bert.alert('If you are under 13 years of age, then please do not use the service.', 'danger');
    } else if (this.state.birthday === 'N/A' || this.state.birthmonth === 'N/A' || this.state.birthyear === 'N/A' || this.state.sex === 'N/A') {
      Bert.alert('Please complete all required fields.', 'danger');
    } else {
      const birthdateFormatted = `${this.state.birthmonth}-${this.state.birthday}-${this.state.birthyear}`;
      const settingsObj = {
        userId: Meteor.userId(),
        birthmonth: this.state.birthmonth,
        birthday: this.state.birthday,
        birthyear: this.state.birthyear,
        birthdate: birthdateFormatted,
        sex: this.state.sex,
        expertise: this.state.expertise,
        country: this.state.country,
        state: this.state.state,
        industry: this.state.industry,
        income: this.state.income,
        education: this.state.education,
      };

      upsertUserProfile.call(settingsObj, (error, response) => {
        if (error) {
          Bert.alert('Save unsuccessful.', 'danger');
        } else {
          if (this.state.tourRunning) {
            changeIntroTour.call(tourObj);

            browserHistory.push('/user/settings');
          }
          Bert.alert('Save successful!', 'success');
        }
      });
    }
  }

  render() {
    const countries = countryList();
    const states = statesList();
    const industries = industryList();
    const incomes = incomesList();
    const months = monthsList();
    const educations = educationsList();

    if (!this.props.ready) {
      return (
        <div>Loading user profile...</div>
        );
    }

    return (
      <ProfileForm {...this.state} months={ months } dayOptions={ dayOptions } yearOptions={ yearOptions } expertise={ expertiseOptions } countries={ countries }
        states={ states } industries={ industries } incomes={ incomes } educations={ educations } handleChange={ this.handleChange } upsertToDB={ this.upsertToDB }
        profileIntro={ profileIntro } />
      );
  }
}

ProfileFormContainer.PropTypes = {
  ready: React.PropTypes.bool,
  profile: React.PropTypes.array,
};

export default createContainer(() => {
  const userProfile = Meteor.subscribe('userProfile', Meteor.userId());
  const introTour = Meteor.subscribe('introTour', Meteor.userId());
  return {
    ready: userProfile.ready(),
    profile: UserProfile.find({}).fetch(),
    intro: IntroTour.find({}).fetch(),
  };
}, ProfileFormContainer);

这是反应路由器代码

 <Router history={browserHistory}>
      <Route name="Home" path="/" component={Main} >
        <IndexRoute component={Index} onEnter={authenticate} />
        <Route name="Asset Allocation" path="/asset-allocation" 
component={AssetAllocation} />
        <Route name="Recover Password" path="/recover-password" 
component={RecoverPassword} />
        <Route name="Reset Password" path="/reset-password/:token" 
component={ResetPassword} />
        <Route name="User" path="/user" component={Profile}>
          <Route name="About" path="/user/home" component={User} />
          <Route name="Profile" path="/user/profile" component=
{ProfileForm} />
          <Route name="Settings" path="/user/settings" component=
{SettingsForm} />
        </Route>
      </Route>
      <Route component={Blank}>
        <Route name="Login" path="/login" component={Login} onEnter=
{loggedIn} />
        <Route name="Signup" path="/signup" component={Signup} onEnter=
{loggedIn} />
        <Route name="Not Found" path="*" component={NotFound} onEnter=
{notFound} />
      </Route>
    </Router>,

1 个答案:

答案 0 :(得分:0)

这来自react-router/v3/docs

<Router>
  <Route path="/" component={App}>
    <Route path="about" component={About} />
    <Route path="inbox" component={Inbox}>
      <Route path="messages/:id" component={Message} />
    </Route>
  </Route>
</Router>

注意嵌套路由没有前导或尾部斜杠。遵循该惯例,我认为您将解决您的问题。

编辑:回复你的评论。

这是来自React componentWillReceiveProps文档:

  

在安装过程中,React不会使用初始道具调用componentWillReceiveProps。如果某些组件的道具可能会更新,它只会调用此方法。调用this.setState通常不会触发componentWillReceiveProps。

尝试将数据检索功能移至componentDidMount生命周期挂钩。