【问题标题】:Next.js keeps current page active and re-rendering while getInitialProps of next page finishes loadingNext.js 在下一页的 getInitialProps 完成加载时保持当前页面处于活动状态并重新渲染
【发布时间】:2020-01-28 00:41:24
【问题描述】:

场景是这样的:

  1. 在一页 (AssessmentListPage) 中,我显示了现有评估的列表;在第二页 (AssessmentDetailPage) 中,我将显示所选评估的详细信息;
  2. 我正在使用 redux,两个页面都使用相同的 slice 操作系统状态 (assessments)
  3. 当我从AssessmentListPage 移动到AssessmentDetailPage 时,一切正常;当我点击后退按钮时,它崩溃了。
  4. 崩溃的原因:Next.js 保持AssessmentDetailPage 页面处于活动状态,直到static getInitialProps 方法完成。被调用的操作会更改状态并导致当前页面在没有预期数据的情况下重新呈现。然后正确渲染AssessmentListPage

处理这个问题的最优雅的方法是什么?我应该分开减速器吗?

目前我只是更具防御性,并添加了我通常不需要的检查来避免这种特定的崩溃。

我还考虑过不在getInitialProps 中加载数据,而是在componentDidMount() 中加载数据,但我不喜欢复制代码来处理服务器端和客户端渲染的想法。

非常感谢任何建议。谢谢!

class AssessmentListPage extends React.Component {
  static async getInitialProps({ store, req }) {
    await store.dispatch(loadProfile(api)(req))
    await store.dispatch(loadAssessments(api)(req))
  }
}

class AssessmentDetailPage extends React.Component {
  static async getInitialProps({ store, req }) {
    await store.dispatch(loadProfile(api)(req))
    await store.dispatch(loadAssessment(api)(req, query.id))
  }
}

【问题讨论】:

  • 你能发布记录的错误吗?
  • 我认为这个错误并不重要。基本上,列表页面需要一个浅对象,而详细信息页面需要“完整对象”。发生错误是因为当页面加载浅版本以移动到列表页面时,详细页面仍然处于活动状态并重新呈现导致页面崩溃,因为它试图访问不存在的数据。
  • 你能在codesandbox中进行复制吗?返回一个包含 setTimeout 的 Promise 来模拟延迟

标签: reactjs react-redux next.js


【解决方案1】:

如果你使用 Redux 来同步多个组件之间的状态是因为这里暴露的原因之一:https://medium.com/@dan_abramov/you-might-not-need-redux-be46360cf367,没关系。但如果只是因为你想重用加载部分,那么“一种优雅的方式”应该是为每个页面使用本地状态,并将所有加载代码放在一个 HOC 中:

// withAssessmentInfo.js
export default (WrappedComponent) => {
  return class AssessmentInfo extends React.Component {
     static async getInitialProps (context) {
        const props = await super.getInitialProps(context)
        props.profile = await loadProfile(api)(context.req)
        props.assessment = await loadAssessment(api)(context.req, context.req.query.id)
   }

   return {
    ...(WrappedComponent.getInitialProps ? await WrappedComponent.getInitialProps(context) : {}),
    ...props
   }
 }

 render () {
   return (
    <WrappedComponent {...this.props} />
   )
 }
}}

所以现在,你可以这样加载数据:

class AssessmentListPage extends React.PureComponent {
   static propTypes = {
     profile: PropTypes.object.isRequired,
     assessment: PropTypes.array.isRequired
   }

   static async getInitialProps(context) {
      // load specific data for this page here
   }

   render () {
     const { profile, assessment } = this.props

     if (profile && assessment) {
       <div>your component code</div>
     } else {
       return (
         <div>Loading some data...</div>
       )
     }
   }
}

export default withAssessmentInfo(AssessmentListPage)

AssessmentDetailPage 的想法相同。

参考资料:

https://reactjs.org/docs/higher-order-components.html https://medium.com/@Farzad_YZ/handle-loadings-in-react-by-using-higher-order-components-2ee8de9c3deb https://medium.com/@mcculloughjchris/fetching-data-with-a-higher-order-component-in-react-43c622c30a82 https://medium.com/@guigonc/refactoring-moving-api-calls-to-a-higher-order-component-53062c086cb

但是如果你需要或者你想保留 Redux 的理念,那么如果详情页和列表页共享来自 Redux State 的 profile 和评估 props,那么你应该添加到 Redux State 和 indicator 以便协调所有数据加载:

// Redux State
{
  assessmentData: {
     operation: 'ready', // ready || loading
     profile: null,
     assessments: null
  }
}

如果您总是一起加载配置文件和评估,您可以使用异步操作来加载它们(https://github.com/reduxjs/redux-thunk)或使用中间件:

export default store => next => action => {
    const result = next(action)

    if (action.type === LOAD_ASSESSMENT_INFO) {
       store.dispatch({
         type: LOADING_ASSESSMENT_INFO // the action put the loading state
       })
       const profile = await loadProfile(api)
       const assessment = await loadAssessment(api)(action.payload.id)

       store.dispatch({
         type: LOADED_ASSESSMENT_INFO, // this action put the ready state, and set the data
         payload: {
           profile,
           assessment
         }
       })
    }

    return result
}

即便如此,你应该阅读这个链接How to to cancel pending asynchronous actions in React/Redux,并且你应该防止在异步操作应该被取消时继续加载。

我希望这些信息可以帮助您找到构建项目以处理使用 NextJS 加载数据的最佳方式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-01-25
    • 1970-01-01
    • 1970-01-01
    • 2012-05-18
    • 1970-01-01
    • 2019-02-25
    • 2019-11-17
    • 2013-05-24
    相关资源
    最近更新 更多