Next.js 在下一页的 getInitialProps 完成加载时保持当前页面处于活动状态并重新渲染
Posted
技术标签:
【中文标题】Next.js 在下一页的 getInitialProps 完成加载时保持当前页面处于活动状态并重新渲染【英文标题】:Next.js keeps current page active and re-rendering while getInitialProps of next page finishes loading 【发布时间】:2020-01-28 00:41:24 【问题描述】:场景是这样的:
-
在一页 (
AssessmentListPage
) 中,我显示了现有评估的列表;在第二页 (AssessmentDetailPage
) 中,我将显示所选评估的详细信息;
我正在使用 redux,两个页面都使用相同的 slice 操作系统状态 (assessments
)
当我从AssessmentListPage
移动到AssessmentDetailPage
时,一切正常;当我点击后退按钮时,它崩溃了。
崩溃的原因: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 来模拟延迟 【参考方案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 加载数据的最佳方式。
【讨论】:
以上是关于Next.js 在下一页的 getInitialProps 完成加载时保持当前页面处于活动状态并重新渲染的主要内容,如果未能解决你的问题,请参考以下文章
Angular 8. 如何在登录页面单击登录按钮,并在下一页的导航栏组件上显示用户名?