【问题标题】:React: Dynamic route not re-rendering correctly反应:动态路线未正确重新渲染
【发布时间】:2018-10-19 01:15:25
【问题描述】:

Codesandbox Repo

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

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

有人告诉我直接在 this.state 内部使用 this.props 是一个糟糕的选择,而是使用 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']
};

【问题讨论】:

    标签: reactjs state render react-props


    【解决方案1】:

    您可以使用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>
        )
      }
    };
    

    更新

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

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

    【讨论】:

    • 感谢您,特别是向我展示了如何使用getDerivedStateFromProps。我也想知道你能不能回答我的第二个问题。这是state 的正确用例还是使用函数组件并映射到数组就可以了?
    • @BrandonBenefield 答案已更新,希望能解决您的疑惑
    猜你喜欢
    • 1970-01-01
    • 2019-02-03
    • 2021-02-09
    • 2022-11-25
    • 2017-12-23
    • 2021-07-22
    • 1970-01-01
    • 2014-09-23
    • 1970-01-01
    相关资源
    最近更新 更多