当 prop 更改时重新渲染 React 组件

新手上路,请多包涵

我正在尝试将展示组件与容器组件分开。我有一个 SitesTable 和一个 SitesTableContainer 。容器负责触发 redux 操作以根据当前用户获取适当的站点。

问题是在容器组件最初呈现之后,当前用户是异步获取的。这意味着容器组件不知道它需要重新执行其 componentDidMount 函数中的代码,该函数将更新数据以发送到 SitesTable 。我认为当容器组件之一的道具(用户)发生更改时,我需要重新渲染容器组件。我该如何正确地做到这一点?

 class SitesTableContainer extends React.Component {
    static get propTypes() {
      return {
        sites: React.PropTypes.object,
        user: React.PropTypes.object,
        isManager: React.PropTypes.boolean
      }
     }

    componentDidMount() {
      if (this.props.isManager) {
        this.props.dispatch(actions.fetchAllSites())
      } else {
        const currentUserId = this.props.user.get('id')
        this.props.dispatch(actions.fetchUsersSites(currentUserId))
      }
    }

    render() {
      return <SitesTable sites={this.props.sites}/>
    }
}

function mapStateToProps(state) {
  const user = userUtils.getCurrentUser(state)

  return {
    sites: state.get('sites'),
    user,
    isManager: userUtils.isManager(user)
  }
}

export default connect(mapStateToProps)(SitesTableContainer);

原文由 David 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 694
2 个回答

您必须在 componentDidUpdate 方法中添加一个条件。

该示例使用 fast-deep-equal 来比较对象。

 import equal from 'fast-deep-equal'

...

constructor(){
  this.updateUser = this.updateUser.bind(this);
}

componentDidMount() {
  this.updateUser();
}

componentDidUpdate(prevProps) {
  if(!equal(this.props.user, prevProps.user)) // Check if it's a new user, you can also use some unique property, like the ID  (this.props.user.id !== prevProps.user.id)
  {
    this.updateUser();
  }
}

updateUser() {
  if (this.props.isManager) {
    this.props.dispatch(actions.fetchAllSites())
  } else {
    const currentUserId = this.props.user.get('id')
    this.props.dispatch(actions.fetchUsersSites(currentUserId))
  }
}

使用 Hooks (React 16.8.0+)

 import React, { useEffect } from 'react';

const SitesTableContainer = ({
  user,
  isManager,
  dispatch,
  sites,
}) => {
  useEffect(() => {
    if(isManager) {
      dispatch(actions.fetchAllSites())
    } else {
      const currentUserId = user.get('id')
      dispatch(actions.fetchUsersSites(currentUserId))
    }
  }, [user]);

  return (
    return <SitesTable sites={sites}/>
  )

}

如果您要比较的道具是对象或数组,则应使用 useDeepCompareEffect 而不是 useEffect

原文由 QoP 发布,翻译遵循 CC BY-SA 4.0 许可协议

componentWillReceiveProps() 由于错误和不一致,将来将被弃用。在道具更改时重新渲染组件的替代解决方案是使用 componentDidUpdate()shouldComponentUpdate()

componentDidUpdate() is called whenever the component updates AND if shouldComponentUpdate() returns true (If shouldComponentUpdate() is not defined it returns true by default).

 shouldComponentUpdate(nextProps){
    return nextProps.changedProp !== this.state.changedProp;
}

componentDidUpdate(props){
    // Desired operations: ex setting state
}

通过在其中包含条件语句,仅使用 componentDidUpdate() 方法即可完成相同的行为。

 componentDidUpdate(prevProps){
    if(prevProps.changedProp !== this.props.changedProp){
        this.setState({
            changedProp: this.props.changedProp
        });
    }
}

如果尝试在没有条件或没有定义的情况下设置状态 shouldComponentUpdate() 组件将无限重新渲染

原文由 ob1 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进