Реакция: Динамический маршрут не перерисовывается правильно - PullRequest
0 голосов
/ 09 мая 2018

Codesandbox Repo

Изучая динамические маршруты с помощью react router 4 и при этом решила реорганизовать функциональный компонент в компонент класса.Причина этого и исправьте меня, если я ошибаюсь, заключается в том, что компонент TopNavSub получает информацию от react router 4 из this.props.match.params.<var> и выбирает, что визуализировать.

Для меня это звучит как изменение состояния.Единственное, в чем я сомневаюсь, это то, что состояние НИКОГДА не изменится на одном и том же маршруте и ВСЕГДА будет отличаться для каждого маршрута, поэтому я не уверен, совпадает ли это с состоянием обработки или нет.Например, /mac будет отображать только элементы в массиве mac и т. Д.

Мне сказали, что использование this.props непосредственно внутри this.state - плохой выбор, и вместо этого следует использовать componentWillReceiveProps(), ноПохоже, что команда разработчиков реагирует на это плохо, UNSAFE_componentWillReceiveProps () , и, тем не менее, она ничего не решила.

TLDR;
Таким образом, проблема заключается в том, что после рефакторингамои данные отображаются только для первого начального маршрута, и независимо от того, какой маршрут будет выбран позднее, будут отображаться только исходные данные выбранного маршрута, если они не обновлены (f5).

TopNavSub.js

import React, { Component } from 'react';

// data
import { subNavLinks } from './navigationData';

class TopNavSub extends Component {
  constructor(props) {
    super(props);
    this.state = {
      navLinks        : { ...subNavLinks },
      product         : this.props.match.params.product,
      currentProduct  : Object.keys(subNavLinks).filter(subNavLinksKey => subNavLinksKey === this.props.match.params.product),
    }
  }

  render() {
    return (
      (!this.state.navLinks)
      ?
        null
      :
        <ul>
          {
            this.state.navLinks[this.state.product].map(product => {
              return (
                <li key={ product }>{ product }</li>
              )
            })
          }
        </ul>
    )
  }
};

export default TopNavSub;

navigationData.js

export const subNavLinks = {
  mac: ['MacBook', 'MacBook Air', 'MacBook Pro', 'iMac', 'iMac Pro', 'Mac Pro', 'Mac Mini', 'Accessories', 'High Sierra', 'Compare'],
  ipad: ['iPad Pro', 'iPad', 'iPad Mini 4', 'iOS 11', 'Accessories', 'Compare'],
  iphone: ['iPhone X', 'iPhone 8', 'iPhone 7', 'iPhone 6s', 'iPhone SE', 'iOS 11', 'Accessories', 'Compare'],
  watch: ['Apple Watch 3', 'Apple Watch Nike+', 'Apple Watch Hermes', 'Apple Watch Edition', 'Apple Watch 1', 'Watch OS', 'Bands', 'Accessories', 'Compare'],
  tv: ['Apple TV 4k', 'Apple TV', 'TV App', 'Accessories', 'Compare'],
  music: ['Apple Music', 'iTunes', 'HomePod', 'iPod Touch', 'Music Accessories', 'Gift Cards'],
  support: ['Apple doesn\'t support anything older than iOS11']
};

1 Ответ

0 голосов
/ 09 мая 2018

Вы можете решить свою проблему либо с помощью componentWillReceiveProps, либо, если хотите, чтобы она была в будущем, с новым статическим getDerivedStateFromProps.

class TopNavSub extends Component {
  constructor(props) {
    super(props);
    //This could be extracted to avoid repetition, I'm copy-pasting it
    const currentProduct = Object.keys(subNavLinks)
      .filter(subNavLinksKey => subNavLinksKey === this.props.match.params.product);
    this.state = {
      navLinks: subNavLinks[currentProduct[0]],
      product: this.props.match.params.product,
      currentProduct
    }
  }

  //IMPORTANT: USE EITHER ONE OR THE OTHER
  //I wrote both options for demonstration purposes

  componentWillReceiveProps(nextProps, prevState) {
    const currentProduct = Object.keys(subNavLinks)
      .filter(subNavLinksKey => subNavLinksKey === nextProps.match.params.product);
    this.setState({
      product: nextProps.match.params.product,
      navLinks: subNavLinks[currentProduct[0]],
      currentProduct
    });
  }

  static getDerivedStateFromProps(nextProps, prevState) {
    const currentProduct = Object.keys(subNavLinks)
      .filter(subNavLinksKey => subNavLinksKey === nextProps.match.params.product);
    return {
      product: nextProps.match.params.product,
      navLinks: subNavLinks[currentProduct[0]],
      currentProduct
    };
  }

  render() {
    return (
      (!this.state.navLinks)
        ?
        null
        :
        <ul>
          {
            this.state.navLinks.map(product => {
              return (
                <li key={product}>{product}</li>
              )
            })
          }
        </ul>
    )
  }
};

UPDATE

Что касается вашего второго вопроса, хорошее общее правило состоит в том, что если вам не нужно обрабатывать события пользовательского ввода или хранить внешние данные (например, данные из внутреннего API), вы ("" "ВЕРОЯТНО" "") не Не нужно состояние компонента. В этом случае вы извлекаете все состояние из реквизита и не обрабатываете события, поэтому вы можете написать этот компонент просто как функцию, подобную этой:

const TopNavSub = props => {

    //Since you're using ES6 you can change filter for find to get a single element instead of an array
    const currentProduct = Object.keys(subNavLinks)
        .find(subNavLinksKey => subNavLinksKey === props.match.params.product);
    const navLinks = subNavLinks[currentProduct];

    return (
        (!navLinks)
        ?
            null
        :
            <ul>
            {
                navLinks.map(product => (li key={product}>{product}</li>))
            }
            </ul>
    );
};
...