对道具更改做出反应重新渲染

React rerender on prop change

我的问题是,当我更改 redux 存储内的状态并根据此状态安装或卸载组件时。代码如下所示:

class Main extends Component {

  render() {
    const { dropdownState } = this.props;
    return (
      <div>
        <SecondHeadBar />
        <div className="main">
          <Switch>
            <Route exact path='/' component={withRouter(WebsiteIndex)}/>
            <Route path='/track/:trackid' component={withRouter(MssTrack)}/>
            <Route path='/album/:albumid' component={withRouter(Container.AlbumContainer)}/>
            <Route path='/profile/:userName' component={withRouter(MssUser)}/>
            <Route path='/upload/:albumid' component={withRouter(MssUploadTemplate)}/>
            <Route path='/upload' component={withRouter(MssUploadTemplate)}/>
            <Route path='/admin' component={withRouter(ControlCenter)}/>
            <Route path='/kategorie' component={withRouter(Category)} exact/>
            <Route path='/kategorie/:catName' component={withRouter(Folder)}/>
            <Route path='/notFound' component={withRouter(NotFound)}/>
            <Route path='/meine-eintraege' component={withRouter(Container.MyEntriesContainer)}/>
          </Switch>
        </div>
        {dropdownState ? <DownloadDropdown /> : ''}
      </div>
    );
  }
}

function mapStateToProps(state) {
  return {
    dropdownState: state.collection.dropdownState
  };
}

function mapDispatchToProps(dispatch) {
  return {
    dispatch
  };
}


export default connect(mapStateToProps, mapDispatchToProps)(Main);

每当道具 dropdownState 改变时。组件 DownloadDropdown 被挂载,然后 Main 组件中的所有内容都被重新渲染。所以内容一闪而过。

我想你可以使用这个生命周期方法来检查。

 static getDerivedStateFromProps(nextProps, prevState) {
        if (nextProps.name !== prevState.name) {
            return { name: nextProps.name};
        }
    }

或对于旧版本,请签入 componentwillreceiveProps 并停止重新渲染。

最简单的解决方案是让 <DownloadDropdown /> 成为连接到 Redux 的容器组件,并且将始终保持挂载状态 尽管不可见 。然后你可以利用 HOC 或始终安装和可见的东西(如 <SecondHeadBar />)并将其连接到切换 DownloadDropdown 可见性的 Redux action creator。换句话说,将 Redux 隔离为两个组件,而不是整个路由树。

工作示例:https://codesandbox.io/s/yw4m7yz8r1(浏览路线并单击顶部的 'Download Schedule' link!)

我不确定你是如何触发 mount/unmount 的,但让我们让它通过按钮切换:

SecondHeadBar.js

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { handleDropdown } from '../actions';

class SecondHeadBar extends Component {
  state = {...}

  componentDidMount = () => { ... }

  render = () => (
    <div>
      ...
      <button onClick={this.props.handleDropdown}>Toggle Dropdown</button>
      ...
    </div>
  )
}

export default connect(null, { handleDropdown })(SecondHeadBar)

DownloadDropdown.js

import React, { Component } from 'react';
import { connect } from 'react-redux';

class DownloadDropdown extends Component {
  state = { ... }

  componentDidMount = () => { ... }


  render = () => (
    this.props.isVisible
      ? <div>I'm visible!</div>
      : null
  )
}

export default connect(state => ({ isVisible: state.dropdown }))(DownloadDropdown)

actions.js

import { TOGGLE_DROPDOWN } from '../types'


export const handleDropdown = () => ({
  type: TOGGLE_DROPDOWN
})

reducers.js

import { TOGGLE_DOWN } from '../types';

...

const dropdownReducer = (state=false, { type, payload }) => {
  switch(type) {
    case TOGGLE_DROPDOWN: return !state
    default: return state
  }
}

export default = combineReducer({
  ...
  dropdown: dropdownReducer
  ...
})

routes.js

const Main = () => (
  <div>
    <SecondHeadBar />
    <div className="main">
      <Switch>
        <Route exact path='/' component={withRouter(WebsiteIndex)}/>
        <Route path='/track/:trackid' component={withRouter(MssTrack)}/>
        <Route path='/album/:albumid' component={withRouter(Container.AlbumContainer)}/>
        <Route path='/profile/:userName' component={withRouter(MssUser)}/>
        <Route path='/upload/:albumid' component={withRouter(MssUploadTemplate)}/>
        <Route path='/upload' component={withRouter(MssUploadTemplate)}/>
        <Route path='/admin' component={withRouter(ControlCenter)}/>
        <Route path='/kategorie' component={withRouter(Category)} exact/>
        <Route path='/kategorie/:catName' component={withRouter(Folder)}/>
        <Route path='/notFound' component={withRouter(NotFound)}/>
        <Route path='/meine-eintraege' component={withRouter(Container.MyEntriesContainer)}/>
      </Switch>
    </div>
    <DownloadDropdown/>
  </div>
);

export default Main;

现在,当用户单击 <SecondHeadBar/> 中的 "Toggle Dropdown" 按钮时,它将更新 <DownloadDropdown/> 的可见性,而不会影响您的路线树。