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

Re-render React component when prop changes

我正在尝试将展示组件与容器组件分开。我有一个 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);
componentWillReceiveProps(nextProps) { // your code here}

我认为这就是您需要的活动。 componentWillReceiveProps 每当你的组件通过 props 接收到东西时触发。从那里你可以进行检查,然后做任何你想做的事情。

我建议您看看我的 ,看看它是否与您正在做的事情相关。如果我理解你的真正问题,那就是你没有正确使用你的异步操作并更新 redux "store",它会自动用它的新道具更新你的组件。

您的这部分代码:

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,但它会帮助你推理这样的场景并编写代码来匹配。

您必须在 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}/>
  )

}

如果你比较的prop是一个对象或者数组,你应该使用useDeepCompareEffect instead of useEffect.

由于错误和不一致,

componentWillReceiveProps() 将来会被弃用。在 props 更改时重新渲染组件的另一种解决方案是使用 componentDidUpdate()shouldComponentUpdate().

每当组件更新时调用

componentDidUpdate() 并且如果 shouldComponentUpdate() returns 为真(如果未定义 shouldComponentUpdate() returns 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
        });
    }
}

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

您可以使用 KEY 随 props 变化的唯一键(数据的组合),并且该组件将使用更新的 props 重新渲染。

一个友好的使用方法如下,一旦道具更新它会自动重新渲染组件:

render {

let textWhenComponentUpdate = this.props.text 

return (
<View>
  <Text>{textWhenComponentUpdate}</Text>
</View>
)

}

您可以在要重新呈现的组件中使用 getDerivedStateFromProps() 生命周期方法,根据传递给组件的 props 的传入更改来设置其状态。更新状态将导致重新渲染。它是这样工作的:

static getDerivedStateFromProps(nextProps, prevState) {
  return { myStateProperty: nextProps.myProp};
}

这会将组件状态中 myStateProperty 的值设置为 myProp 的值,并且组件将重新渲染。

确保您了解使用此方法的潜在影响。特别是,您需要避免无意中覆盖组件的状态,因为 props 在父组件中意外更新。如果需要,您可以通过将现有状态(由 prevState 表示)与任何传入的 props 值进行比较来执行检查逻辑。

只有在 props 的值是状态值的真实来源的情况下,才使用更新的 prop 来更新状态。如果是这样的话,可能还有更简单的方法来实现您的需要。参见 - You Probably Don't Need Derived State – React Blog.