高阶组件状态正在正确更新,但接收道具的包装组件不会在状态更改时重新渲染

Posted

技术标签:

【中文标题】高阶组件状态正在正确更新,但接收道具的包装组件不会在状态更改时重新渲染【英文标题】:Higher Order Component state is updating correctly but wrapped component receiving props not re-rendering on state change 【发布时间】:2020-09-22 06:47:45 【问题描述】:

我有这个 HOC,它将 dailyTime 传递到一个包装组件中,其唯一功能是显示花费的时间。它在初始渲染/页面加载时接收它的道具很好。接收 updateTime 道具并在练习完成时调用 getDailyStats 的第二个组件被正确调用,并且 getDailyStats 正在运行,并且 HOC 中的状态正在更新(渲染中的 console.log 总是在更新)但是我的包装组件是接收该更新是在状态更改时重新呈现。我想知道它是否与重组无关?无论如何,我们将不胜感激任何帮助!

const withDailyStats = WrappedComponent => 

  class withDailyStats extends React.Component 
    constructor(props) 
      super(props);
      this.state = 
      ;
    


  getDailyStats = async () => 
    const authUser = this.props.authUser.uid
    let userSets = await this.props.firebase.sets()
      .where('userId', '==', authUser)
      .get()

    let data = userSets.docs.map(doc => doc.data());
    let now = moment()
    let pastDay =  moment().startOf('day')
    let pastWeek =  moment().startOf('week')

    let todaySets =  data.filter(set => 
      const setTime = moment((set.createdAt.toDate()))
      return setTime >= pastDay
    )

    let todaysTime = todaySets.reduce((a, b) => a + (parseFloat(b['time']) || 0), 0)
    todaysTime = this.msToTime(todaysTime);

    this.setState(
      dailyTime: todaysTime, 
      todaySets
    )
  


   msToTime = (s) => 
    // Pad to 2 or 3 digits, default is 2
    function pad(n, z) 
      z = z || 2;
      return ('00' + n).slice(-z);
   

    var ms = s % 1000;
    s = (s - ms) / 1000;
    var secs = s % 60;
    s = (s - secs) / 60;
    var mins = s % 60;
    var hrs = (s - mins) / 60;

    return pad(hrs) + ':' + pad(mins) + ':' + pad(secs) 
  

    componentDidMount() 
      this.getDailyStats()
    


    render() 
      console.log('HOC STATE', this.state.dailyTime)
      return <WrappedComponent dailyTime=this.state.dailyTime ...this.props updateTime=. 
              this.getDailyStats />;
    
  ;

return compose(
  withFirebase, 
  withAuthentication,
  )(withDailyStats);


export default withDailyStats;

这是未更新的包装组件。它曾经是功能性的,但我将它更改为一个类组件,只是作为一个测试。

class DailyStatModule extends React.Component  
  state = 

  componentDidMount() 
    console.log('daily mount', this.props.dailyTime)
  


  render() 
    console.log('DSM', this.props)
    return (
      <DailyWrapper >
        <div style=textAlign: "center">
          <FontAwesomeIcon icon=faClock sz="lg" />
          <div>this.props.dailyTime</div>
        </div>
      </DailyWrapper>
    );
  





export default withDailyStats(DailyStatModule)

【问题讨论】:

是否有任何理由让 HOC 和组件具有相同的 withDailyStats 名称?我只是想知道 compose 函数是否使用 HOC 而不是组件。您可以尝试重命名其中一个吗? 刚刚尝试使用 wtihDailyStatsWrapper 重命名包装器并导入...没有用。认为它可能有效,似乎是个好主意.... @VishalSharma 【参考方案1】:

您的 withDailyStats hoc 正被 2 个组件使用。 getDailyStatsComponent1 执行,它更新 withDailyStats 的状态。此更新不会传播到DailyStatModule 组件。对不起。

从设计上讲,React 是一种数据流方式。在您的情况下,您可以使用 context api 或 redux 或

另外,看看here 和here

【讨论】:

是的,我试图避免使用 redux。虽然,这一切都说得通。只会添加一个上下文提供者/消费者。【参考方案2】:

根据您的代码,我假设包装的组件最初只呈现一次,因为使用了 componentDidMount?

我认为您可能想在包装的组件上尝试 componentDidUpdate 来比较 props 以进行后续更新。

这里的详细信息: https://reactjs.org/docs/react-component.html#componentdidupdate

【讨论】:

以上是关于高阶组件状态正在正确更新,但接收道具的包装组件不会在状态更改时重新渲染的主要内容,如果未能解决你的问题,请参考以下文章

更新高阶组件中的道具

仅在父状态更新后如何接收道具?

通过 React 高阶组件传递子道具的正确 TypeScript 类型

Redux - 状态正在更新,但 React 组件没有

react 高阶组件

更新道具时反应本机组件不透明度不更新