React:动态路由无法正确重新呈现

时间:2018-05-09 02:13:15

标签: reactjs state render react-props

Codesandbox Repo

了解react router 4的动态路由,并在此过程中决定将函数组件重构为类组件。这背后的原因,如果我错了,请纠正我的是TopNavSub组件从react router 4 this.props.match.params.<var>获取信息并选择要呈现的内容。

对我来说,这听起来像是状态的变化。唯一让我怀疑的是,状态永远不会在同一条路线上改变,并且每条路线总是不同的,所以我不确定这是否与处理状态相同。例如,/mac只会映射mac数组等中的项目。

我被告知直接在this.props内使用this.state是一个糟糕的选择,而是使用componentWillReceiveProps(),但React团队似乎对此感到不满,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 :(得分:1)

您可以使用Any解决问题,或者,如果您希望使用新的静态componentWillReceiveProps,则可以解决问题。

getDerivedStateFromProps

<强>更新

关于第二个问题,一个好的一般规则是,如果您不需要处理用户输入事件或保存外部数据(例如来自后端API的数据),那么(&#34;&#34; &#34;可能&#34;&#34;&#34;)不需要组件状态。在这种情况下,您从props中获取整个状态而不进行任何事件处理,因此您可以将此组件简单地编写为如下函数:

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>
    )
  }
};