首页 文章

当道具改变时,重新渲染反应成分

提问于
浏览
40

我正在尝试将表示组件与容器组件分开 . 我有 SitesTableSitesTableContainer . 容器负责触发redux操作以基于当前用户获取适当的站点 . 问题是在最初呈现容器组件之后,异步获取当前用户 . 这意味着容器组件不知道它需要在其 componentDidMount 函数中重新执行代码,这将更新要发送到 SitesTable 的数据 . 我想我需要在其中一个props(用户)更改时重新呈现容器组件 . 我该怎么做?

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

5 回答

  • 2

    您必须在 componentWillReceiveProps 方法中添加条件 .

    这就是组件的外观

    constructor(){
      this.updateUser = this.updateUser.bind(this);
    }  
    
    
    componentDidMount() {
      this.updateUser();
    
    }
    
    componentWillReceiveProps(nextProps) {
        if(JSON.stringify(this.props.user) !== JSON.stringify(nextProps.user)) // Check if it's a new user, you can also use some unique property, like the 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))
      }  
    }
    

    UPDATE (React 17)

    看起来 componentWillReceiveProps 将在React 17中删除 . 您可以使用 componentDidUpdate 而不是 componentWillReceiveProps 来实现相同的功能 .

    新示例使用fast-deep-equal而不是 JSON.stringify() 来比较对象 .

    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))
      }  
    }
    
  • -1

    由于错误和不一致, ComponentWillReceiveProps() 将来会被弃用 . 在道具更改上重新渲染组件的替代解决方案是使用 ComponentDidUpdate()ShouldComponentUpdate() .

    每当组件更新时调用 ComponentDidUpdate() 并且如果 ShouldComponentUpdate() 返回true(如果未定义 ShouldComponentUpdate() ,则默认返回 true ) .

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

    If one attempts to set the state without a conditional or without defining ShouldComponentUpdate() the the component will infinitely re-render

  • 5
    componentWillReceiveProps(nextProps) { // your code here}
    

    我认为这是你需要的事件 . 只要您的组件通过道具收到某些内容,就会触发 componentWillReceiveProps . 从那里你可以检查然后做你想做的事 .

  • 56

    我建议看一下我的这个answer,看看它与你在做什么有关 . 如果我理解你真正的问题,那就是新的道具 .

    您的代码的这一部分:

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

    不应该在组件中触发,应在执行第一个请求后处理 .

    redux-thunk看一下这个例子:

    function makeASandwichWithSecretSauce(forPerson) {
    
      // Invert control!
      // Return a function that accepts `dispatch` so we can dispatch later.
      // Thunk middleware knows how to turn thunk async actions into actions.
    
      return function (dispatch) {
        return fetchSecretSauce().then(
          sauce => dispatch(makeASandwich(forPerson, sauce)),
          error => dispatch(apologize('The Sandwich Shop', forPerson, error))
        );
      };
    }
    

    您不一定要使用redux-thunk,但它可以帮助您推理类似这样的场景并编写匹配的代码 .

  • 8

    您可以使用随道具更改的 KEY 唯一键(数据组合),并使用更新的道具重新呈现该组件 .

相关问题