Дочерний компонент подключенного компонента, использующего соединение редукса, не перерисовывается после одного изменения проп - PullRequest
0 голосов
/ 28 ноября 2018

У меня есть главное навигационное меню моего приложения в качестве компонента реакции, подключенного к хранилищу резервов с помощью Connect.Компонент меню также структурирован по разделам, а внутри разделов есть темы.Меню имеет переменные состояния (в магазине), которые указывают, должно ли меню казаться свернутым или нет.Я изменяю статус соответствующим действием и вижу, что внешний вид меню меняется, но внешний вид разделов не меняется.Я передаю значение коллапса как опору, но если не вызывает функцию рендеринга разделов меню, которые будут отрисованы соответственно.

Вот код компонентов Menu и MenuSection:

Menus.jsx

// modules/menu/components/Menu.jsx

import React from 'react'
import PropTypes from 'prop-types'
import classNames from 'classnames'

import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import * as actions from '../actions'

import { MODULE_NAME } from '../constants'
import MenuSection from './MenuSection'

const propTypes = {
  menu: PropTypes.shape({
    sections: PropTypes.array,
    collapsed: PropTypes.bool,
    activeSection: PropTypes.number,
    inflatedSection: PropTypes.number,
    activeTopic: PropTypes.number,
  }).isRequired,
  actions: PropTypes.shape({
    toggle: PropTypes.func,
    activateSection: PropTypes.func,
    toggleSection: PropTypes.func,
  }).isRequired,
}

class Menu extends React.Component {

  constructor(props) {
    super(props)
  }

  toggleMenu = () => this.props.actions.toggleMenu()

  activateSection = (s, t) => this.props.actions.activateSection(s, t)

  toggleSection = (s) => this.props.actions.toggleSection(s)

  render() {
    const collapsed = this.props.menu.collapsed
    const sections = this.props.menu.sections.map((section, i) => {
      const {
        disabled = false,
        icon, text,
        route = { to: '#' },
        topics = [],
      } = section
      const active = this.props.menu.activeSection === i
      const inflated = this.props.menu.inflatedSection === i
      return (
        <MenuSection
          key={i}
          idx={i}
          to={route.to}
          {...{
            icon,
            text,
            topics,
            disabled,
            active,
            inflated,
          }}
          activate={this.activateSection}
          toggle={this.toggleSection}
          activeTopic={this.props.menu.activeTopic}
          collapsed={collapsed}
        />
      )
    })
    const classes = classNames('menu', { collapsed: collapsed })
    const size = collapsed ? 'small' : 'big' 
    return (
      <nav className={classes}>
        <img src={`${process.env.PUBLIC_URL}/imgs/logo-${size}.png`} />
        <ul>
          {sections}
        </ul>
      </nav>
    )
  }

}

Menu.propTypes = propTypes

const mapStateToProps = state => ({ [MODULE_NAME]: state.menu })

const mapDispatchToProps = dispatch => (
  { actions: bindActionCreators(actions, dispatch) }
)

export default connect(mapStateToProps, mapDispatchToProps)(Menu)

MenuSection.jsx

    // modules/menu/components/MenuSection.jsx

import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { NavLink, withRouter } from 'react-router-dom'
import classNames from 'classnames'

import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faCaretDown, faCaretUp } from '@fortawesome/free-solid-svg-icons'

import MenuTopic from './MenuTopic'

const propTypes = {
  idx: PropTypes.number.isRequired,
  to: PropTypes.oneOfType([PropTypes.func, PropTypes.string]).isRequired,
  icon: PropTypes.object.isRequired,
  text: PropTypes.string.isRequired,
  topics: PropTypes.arrayOf(PropTypes.object).isRequired,
  activate: PropTypes.func.isRequired,
  toggle: PropTypes.func.isRequired,
  disabled: PropTypes.bool.isRequired,
  active: PropTypes.bool.isRequired,
  inflated: PropTypes.bool.isRequired,
  activeTopic: PropTypes.number.isRequired,
  collapsed: PropTypes.bool.isRequired
}

class MenuSection extends Component {

  constructor(props) {
    super(props)
    this.onClick = this.onClick.bind(this)
    this.activate = this.activate.bind(this)
  }

  shouldComponentUpdate(nextProps) {
    const { active, inflated, activeTopic } = nextProps;
    return (this.props.active !== active)
      || (this.props.inflated !== inflated) || (this.props.activeTopic !== activeTopic)
  }

  onClick() {
    if (this.props.topics.length > 0) {
      this.props.toggle(this.props.idx)
    } else {
      this.props.activate(this.props.idx, this.props.activeTopic)
    }
  }

  activate(t) {
    this.props.activate(this.props.idx, t)
  }

  render() {
    const { idx, to, icon, text, topics, disabled, active, inflated, activeTopic, collapsed } = this.props
    const items = (inflated ?
      topics.map((topic, i) => (
        <MenuTopic key={i} idx={i} 
          to={topic.route.to} text={topic.text} onClick={this.activate}
          active={active && (activeTopic === i)} section={idx} />))
      : []);
    const classes = classNames({ disabled, active, inflated })
    return (
      <li className={classes}>
        <NavLink to={to} activeClassName="active" onClick={this.onClick}>
          <FontAwesomeIcon icon={icon}  pull="left"/>
          {!collapsed &&
            <React.Fragment>
              {' '}
              {text}
              {topics.length > 0 &&
                <FontAwesomeIcon icon={ inflated ? faCaretUp : faCaretDown } pull="right" />
              }
            </React.Fragment>
          }
        </NavLink>
        {(!collapsed) && inflated &&
          <ul>
            {items}
          </ul>
        }
      </li>)
  }

}

MenuSection.propTypes = propTypes

export default withRouter(MenuSection)

Есть идеи о том, что происходит?Я немного новичок в приложениях с реакцией-редуксом, так что, может быть, я что-то упустил.

Заранее спасибо!

1 Ответ

0 голосов
/ 28 ноября 2018

Похоже, причина не рендеринга в том, что menuSection должен делатьComponentUpdate.Как написано, menuSection будет перерисовываться только в случае изменения props.active, props.inflated или props.activeTopic.Так что если props.collapsed изменился, но больше ничего не изменилось, то рендер пропускается.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...