Как размонтировать компонент при изменении маршрута

У меня есть компонент на заданном маршруте, скажем app.com/cars/1

У меня есть боковая панель со ссылками на разные автомобили, например /cars/2, /cars/3 и т.д.

Проблема, с которой я сталкиваюсь, - это когда вы меняете ссылки, скажем, от cars/1 до cars/2, компонент не отключается, и я получаю componentWillReceiveProps. Если я перейду на другую страницу с другим компонентом, скажем /trucks, компонент будет размонтирован, и все будет хорошо.

Как отключить мой компонент при изменении маршрута? У меня есть все виды состояния и флюса, которые я хочу очистить для этого следующего автомобиля. Или, если не отключить, существует ли типичный способ обращения с такой проблемой? Я не могу себе представить, что это не очень распространено.

(обратите внимание, что я использую реактивный маршрутизатор)

Ответ 1

Я считаю, что нормальный способ справиться с этим - это просто отменить регистрацию и перерегистрацию ваших слушателей, reset ваше состояние и т.д. в componentWillReceiveProps. Нормально создавать абстракции вокруг этого поведения:

componentWillMount: function() {
  this.setupStuff(this.props);
}

componentWillUnmount: function() {
  this.tearDownStuff();
}

componentWillReceiveProps: function(nextProps) {
  this.tearDownStuff();
  this.setupStuff(nextProps);
}

setupStuff: function(props) {
  this.setState(this.getDataFromStore(props.store));
  props.store.listen(this.handler); // or whatever
}

tearDownStuff: function(props) {
  props.store.unlisten(this.handler); // or whatever
}

Однако, если вы действительно хотели перемонтировать свои компоненты, есть несколько вариантов, которые вы можете использовать.

Если вы не хотите, чтобы какой-либо из ваших компонентов оставался установленным во всех изменениях маршрута, вы можете использовать параметр createElement для добавления уникального ключа к компонентам:

function createElement(Component, props) {
  var key = ...; // some key that changes across route changes
  return <Component key={key} {...props} />;
}

// ...

<Router createElement={createElement}>
  ...

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

Если вы хотите, чтобы определенный маршрут всегда был рендерером, вы можете дать ему ключ в родительском объекте через React.cloneElement:

render: function() {
  var key = ...; // some key that changes across route changes
  return React.cloneElement(
    React.Children.only(this.props.children),
    {key: key}
  );
}

Ответ 2

В итоге я закончил:

const createElement = (Component, props) =>
  <Component key={props.params.id} {...props}/>;

ReactDOM.render(
  <Router history={browserHistory} createElement={createElement}>
    <Route path="courses/:id" component={Page_courses_id}/>
  </Router>
);

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