【问题标题】:React rerender on prop change对道具更改做出反应重新渲染
【发布时间】:2019-03-14 05:00:51
【问题描述】:

我的问题是当我在 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 组件中的所有内容都被重新渲染。于是内容一闪而过。

【问题讨论】:

  • 你的问题到底是什么?
  • 如果不清楚,请抱歉。每当道具 dropdownState 发生变化时。并且组件 DownloadDropdown 会在 render() 函数重新渲染的所有内容中安装。所以内容会闪烁,因为它正在从 API 异步加载
  • @ArnaudChrist 我稍微改变了这个问题。希望这能让它更清楚。
  • 与其卸载并重新安装DownloadDropdown,不如将​​dropdownState 作为道具传递给它,然后让它决定何时需要重新渲染/调用服务器。
  • @JoeClay 我也有这个想法,但我不知道这是否是一个不好的做法,因为这样会一直安装 DownloadDropdown。

标签: reactjs redux rerender


【解决方案1】:

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

工作示例:https://codesandbox.io/s/yw4m7yz8r1(浏览路线并点击顶部的“下载时间表”链接!)

我不确定您是如何触发挂载/卸载的,但让我们继续通过按钮切换它:

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)

下载Dropdown.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;

现在,当用户点击&lt;SecondHeadBar/&gt; 中的“切换下拉菜单”按钮时,它会更新&lt;DownloadDropdown/&gt; 的可见性,而不会影响您的路由树。

【讨论】:

    【解决方案2】:

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

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

    或者对于旧版本检查componentwillreceiveProps 并停止重新渲染。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-01-19
      • 2021-05-26
      • 1970-01-01
      • 1970-01-01
      • 2021-01-22
      • 2020-05-01
      • 2021-07-16
      相关资源
      最近更新 更多