Reactjs 当道具更改时重新渲染React组件

Reactjs 当道具更改时重新渲染React组件,reactjs,redux,react-redux,Reactjs,Redux,React Redux,我试图将表示组件与容器组件分开。我有一个SitesTable和一个SitesTableContainer。容器负责触发redux操作,以基于当前用户获取适当的站点 问题在于,在容器组件最初呈现之后,当前用户是异步获取的。这意味着容器组件不知道需要在其componentDidMount函数中重新执行代码,该函数将更新数据以发送到SitesTable。我想当容器组件的一个道具(用户)发生变化时,我需要重新渲染它。如何正确地执行此操作 class SitesTableContainer extends

我试图将表示组件与容器组件分开。我有一个
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);
类SitesTableContainer扩展了React.Component{
静态get propTypes(){
返回{
站点:React.PropTypes.object,
用户:React.PropTypes.object,
isManager:React.PropTypes.boolean
}
}
componentDidMount(){
if(this.props.isManager){
this.props.dispatch(actions.fetchAllSites())
}否则{
const currentUserId=this.props.user.get('id'))
this.props.dispatch(actions.fetchUsersSites(currentUserId))
}  
}
render(){
返回
}
}
函数MapStateTops(状态){
const user=userUtils.getCurrentUser(状态)
返回{
站点:state.get('sites'),
用户,
isManager:userUtils.isManager(用户)
}
}
导出默认连接(MapStateTops)(SitesTableContainer);

我想这是你需要的活动<代码>组件将接收道具在组件通过道具接收到内容时触发。从那里你可以进行检查,然后做任何你想做的事情。

我建议你看看我的这张照片,看看它是否与你正在做的事情相关。如果我理解您真正的问题,那就是您没有正确使用异步操作并更新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,但它将帮助您分析类似的场景,并编写匹配的代码。

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

该示例用于比较对象

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))
  }  
}
使用挂钩(React 16.8.0+)

import React,{useffect}来自“React”;
常数SitesTableContainer=({
用户,
isManager,
派遣,
地点,
}) => {
useffect(()=>{
如果(iManager){
分派(actions.fetchAllSites())
}否则{
const currentUserId=user.get('id')
分派(actions.fetchUsersSites(currentUserId))
}
},[用户];
返回(
返回
)
}

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

ComponentWillReceiveProps()
由于错误和不一致性,将来将不推荐使用。在道具更改时重新呈现组件的另一种解决方案是使用
componentdiddupdate()
ShouldComponentUpdate()

每当组件更新时调用
componentdiddupdate()
,如果
ShouldComponentUpdate()
返回true(如果未定义
ShouldComponentUpdate()
,则默认情况下返回
true

只有使用
componentdiddupdate()
方法,通过在其中包含条件语句,才能实现相同的行为

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

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

您可以使用随道具更改的
唯一键(数据组合),该组件将使用更新的道具重新发布。

一个友好的方法是使用以下道具,一旦道具更新,它将自动重新发布组件:

render {

let textWhenComponentUpdate = this.props.text 

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

}
渲染{
让textWhenComponentUpdate=this.props.text
返回(
{textWhenComponentUpdate}
)
}

您确实有一些其他功能可用,例如componentDidUpdate,或者您正在寻找的功能,componentWillReceiveProps(下一步)如果您想在道具更改时触发某些东西,如果它不更改道具,为什么需要重新渲染SitesTable?@QoP在
componentDidMount
中调度的操作将更改应用程序状态下的
sites
节点,该节点将被传递到
SitesTable
。SitesTable的
sites
节点将发生变化。哦,我明白了,我将写下答案。如何在功能组件中实现这一点,我明白了。但是你在你的组件中将
MakeAsandwithSecretSauce
发送到哪里呢?我会用一个相关的例子将你链接到一个repo,你的应用程序是否使用react router?@David也会很感激这个例子的链接,我基本上有相同的问题。请注意,JSON.stringify只能用于这种比较,如果它是稳定的(根据规范它不是),那么它为相同的输入产生相同的输出。我建议比较用户对象的id属性,或在道具中传递userId-s,并进行比较,以避免不必要的重新加载。请注意,componentWillReceiveProps生命周期方法已弃用,可能会在React 17中删除。React开发团队建议使用componentDidUpdate和新的getDerivedStateFromProps方法的组合。在他们的博文中有更多内容:@QoP第二个例子,使用React钩子,它会在
用户
发生变化时卸载和重新装载吗?这有多贵?这个答案需要提高投票率(至少现在是这样),因为
componentWillReceiveProps
即将被弃用,而且已经过时
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}/>
  )

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

componentDidUpdate(props){
    // Desired operations: ex setting state
}
componentDidUpdate(prevProps){
    if(prevProps.changedProp !== this.props.changedProp){
        this.setState({          
            changedProp: this.props.changedProp
        });
    }
}
render {

let textWhenComponentUpdate = this.props.text 

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

}