React Router master-detail: дочерний компонент не отображает новое представление до обновления страницы

Я создаю навигацию master-detail, как в примере здесь пример реактивного маршрутизатора;

У меня есть компонент контейнера OneCheckpointContainer, который отображает панель навигации CheckpointNav (ссылки), и компонент данных OneCheckpointData (этот парень извлекает данные при загрузке и отображает OneCheckpointView.

Когда я нажимаю одну из ссылок в CheckpointNav, ничего не происходит, кроме изменения URL-адреса в браузере. Только когда я обновлю страницу, новые данные будут извлечены, а затем в дочернем представлении отобразится новый компонент. (ошибок тоже нет)

Я не уверен, что эта ошибка связана с тем, что дочерний компонент также отвечает за получение данных, а также за представление.

Вот как у меня настроены маршруты:

  <Route path="/modules/:id" component={OneCheckpointContainer}>
    <Route path="/modules/:id/checkpoints/:cp_id" component={OneCheckpointData} />
  </Route>

Контейнер OneCheckpoint

import React from 'react';
import CheckpointNav from './CheckpointNav';

class OneCheckpointContainer extends React.Component {
  constructor(props, context) {
    super(props, context);

    this.state = {
      checkpoints: null,
      user: null
    };

  }

  componentWillMount() {
    this.loadCheckpoints();
    this.context.getUser((data) => this.setState({ user: data }));
  }

  loadCheckpoints() {
    $.ajax({
      url: `/api/v1/modules/student/${this.props.params.id}/checkpoints`,
      method: 'GET',
    }).done((data) => {
      this.setState({ checkpoints: data });
    });
  }

  render() {
    return (
      <div>
        <div className="col-xs-3">
          <CheckpointNav mid={this.props.params.id} checkpoints={this.state.checkpoints} />
        </div>
        <div className="col-xs-9">
          { this.props.children || <div>No Children Yet</div>}
        </div>
      </div>
    )
  }
}

OneCheckpointContainer.displayName = OneCheckpointContainer;

OneCheckpointContainer.contextTypes = {
  getUser: React.PropTypes.func.isRequired
};

export default OneCheckpointContainer;

Вот CheckpointNav, хотя я не верю, что ошибка здесь:

import React from 'react';
import NavLink from '../widgets/NavLink';

const CheckpointNav = (props) => {
  const checkpointList = props.checkpoints && props.checkpoints.length > 0 ?
    props.checkpoints.map((item) => {
      return <li key={item.cp._id} className="list-group-item">
      <NavLink className="nav-link" to={"/modules/" + props.mid + "/checkpoints/" + item.cp._id}>
      { item.cp.title}</NavLink></li>
    }) : <div>No CPS</div>;
  return (
    <div className="card one-module-card">
      <div className="card-block modules-card-body">
        <ul className="list-group tags-group">
          { checkpointList }
          <li className="list-group-item new-cp"><NavLink className=""
            to={'/post/checkpoint/' + props.mid}
          >
            New Checkpoint
          </NavLink></li>
        </ul>
      </div>
    </div>
  );

};

export default CheckpointNav;

OneCheckpointData не извлекает новые данные и не отображает новые, пока я не обновлю данные

import React from 'react';
import CheckpointView from './CheckpointView';

class OneCheckpointData extends React.Component {
  constructor(props, context) {
    super(props, context);

    this.state = {
      checkpoint: null,
      user: null
    };

  }

  componentWillMount() {
    this.loadCheckpoint();
    this.context.getUser((data) => this.setState({ user: data }));
  }

  loadCheckpoint() {
    $.ajax({
      url: `/api/v1/modules/three/cp/${this.props.params.cp_id}`,
      method: 'GET',
    }).done((data) => {
      this.setState({ checkpoint: data });
    });
  }

  render() {
    return this.state.checkpoint ? <CheckpointView user={this.state.user} checkpoint={this.state.checkpoint} /> : null;
  }
}

OneCheckpointData.displayName = OneCheckpointData;

OneCheckpointData.contextTypes = {
  getUser: React.PropTypes.func.isRequired
};

export default OneCheckpointData;

** Я не упомянул OneCheckpointView, так как он не имеет значения **


person fresh5447    schedule 25.07.2016    source источник


Ответы (4)


В этом случае вы можете получить реквизиты в качестве параметра функции loadCheckpoing(props) и отправить новые реквизиты на componentWillReceiveProps, как показано ниже.

componentWillMount(this.props) {
  this.loadCheckpoint(this.props);
}

componentWillReceiveProps(nextprops) {
  this.loadCheckpoint(nextprops);
}

loadCheckpoint(props) {
  this.context.getUser((data) => this.setState({ user: data }));
  $.ajax({
    url: `/api/v1/modules/three/cp/${props.params.cp_id}`, //please check i have replace the this.props to props as we have props as a parameter
    method: 'GET',
  }).done((data) => {
    this.setState({ checkpoint: data });
  });
}

я предпочту использовать библиотеку react-redux или reflux для обработки вашего запроса данных ajax, но мое предлагаемое решение должно выполнить эту работу за вас.

person Md.Estiak Ahmmed    schedule 22.08.2016
comment
Думаю, я понимаю, к чему вы стремитесь, но вы не можете передать this.props в качестве аргумента для componentWillMount. - person fresh5447; 01.09.2016

Я думаю, это потому, что вы вызвали функцию loadcheckpoints в componentwillMount. Это вызывается только один раз в жизненном цикле компонента. Поскольку компонент уже смонтирован, когда вы щелкнули ссылку на панели навигации, компонент не будет вызываться. Следовательно, выборка данных не происходит.

Я думаю, вы должны попробовать следующий подход. Функция onclick ссылок в CheckpointNav должна быть передана из OneCheckpointContainer . Загруженные данные должны быть установлены в состояние в контейнере, который будет передавать данные в OneCheckpointData как props.

person bhattshru    schedule 17.08.2016

Два шага к диагностике:

  1. проверьте, вызывался ли ваш метод loadCheckpoint каждый раз, когда вы нажимаете другую ссылку. Просто оставьте одну строку вроде console.log(new Date().toLocaleTimeString()) в этом методе.

  2. если шаг 1 выполнен успешно, проверьте, нет ли в этой части this справочной проблемы: (data) => { this.setState({ checkpoint: data }); }

Кстати, вам лучше поместить вызов ajax в метод componentDidMount. См.: https://facebook.github.io/react/docs/component-specs.html#mounting-componentdidmount

person Max Peng    schedule 19.08.2016

Проблема в том, что ваши компоненты извлекают данные только перед монтированием. Это работает только в первый раз, когда они отображаются. Эти компоненты также должны извлекать свои данные всякий раз, когда они получают новые свойства, например. идентификаторы с маршрутизатора после перехода в новое местоположение.

Для этого самый простой способ — добавить componentWillReceiveProps, который сравнивает предыдущие реквизиты с новыми и при необходимости извлекает новые данные.

Альтернативный способ — добавить обработчик onEnter в конфигурацию Routes, чтобы получать данные при каждом изменении маршрута.

Проверьте ответы на этот вопрос. чтобы увидеть примеры обоих подходов.

person Manolo Santos    schedule 17.08.2016