如何处理 Next.js 中的长时间异步操作以避免页面加载缓慢?
How to handle long async operations in Next.js to avoid slow page loading?
在使用 next-redux-wrapper
时,我如何启动一个长异步任务,以便它在客户端上仅 运行s?我不想在服务器端使用 await
,因为它会延迟初始页面加载。我宁愿在任务开始时设置一个加载标志,并在任务完成之前显示一个加载指示器。
假设我的异步操作是这样的:
function async takesLong(store) {
store.dispatch({type: “LOADING”, payload: true});
const result = await longOperation();
store.dispatch({type: “SETDATA”}, payload: data);
return store.dispatch({type: “LOADING”, payload: false});
}
我可以在下一页的 getInitialProps
函数中这样调用它:
MyPage.getInitialProps = async ({ store, isServer }) => {
const loader = takesLong(store)
if (isServer) await loader; // <-- will delay client response
return {
someprop: "some value"
};
};
如果页面在客户端 上加载,此方法效果很好。操作开始,我的页面可以显示加载微调器,直到操作完成。但是当在 服务器端 启动时,我在页面显示之前有很长的延迟。我已经尝试了多种方法,但找不到一种能正常工作的方法:
- 在服务器上启动进程并且不使用
await
呈现页面而没有将结果写入商店,因此它只在商店中将“loading”设置为 true 而它永远不会获取数据.
- 在我的
props
中传递 store
不起作用 - 它最终成为客户端中的空对象 ({ }
)。
尝试在我的组件中 运行 它似乎不起作用,原因如下:
a) 我在 React 组件中没有可访问的 store
对象(仅在 getInitialProps
中不会在客户端调用)。
b) 即使我在组件中使用动作而不是 store.dispatch
,我什么时候可以安全地调用它?我不能在 render
期间执行此操作,因为它会更改 Redux 状态,并且 componentWillReceiveProps
不会在第一个客户端 render
[=50 之前被调用=]
在使用 Next 时是否有明确定义的模式来将长时间操作推迟到客户端?
在 componentDidMount
上执行长时间的异步任务,它将 运行 仅在客户端执行。
在 SSR 中做出反应,而不是 运行s componentDidMount
生命周期钩子。
在 componentDidMount
期间使用绑定操作有效。感谢@eenagy 的建议。按照这个顺序做事情似乎是在做需要做的事情:
import { bindActionCreators } from "redux";
import { setLoading, setError, setData } from "../actions";
componentDidMount() {
if (!this.props.haveData && !this.props.loading && !this.props.error) {
this.props.setLoading(true);
loadSomeData() // <-- this takes a while to complete
.then( data => {
this.props.setData(data);
this.props.setLoading(false);
})
.catch( err => {
this.props.setError(err);
this.props.setLoading(false);
});
}
}
render() {
if (this.props.loading) return (<Loading/>);
return (/*regular page*/);
}
export const mapDispatchToProps = dispatch => {
return bindActionCreators({ setLoading, setError, setData }, dispatch);
};
export default connect(mapStateToProps, mapDispatchToProps)(Component);
这样,如果初始数据尚未加载(比如由另一个页面加载),它将在
组件挂载和 运行 异步直到操作完成并且
调用 redux 中的操作使页面变为 re-render.
在使用 next-redux-wrapper
时,我如何启动一个长异步任务,以便它在客户端上仅 运行s?我不想在服务器端使用 await
,因为它会延迟初始页面加载。我宁愿在任务开始时设置一个加载标志,并在任务完成之前显示一个加载指示器。
假设我的异步操作是这样的:
function async takesLong(store) {
store.dispatch({type: “LOADING”, payload: true});
const result = await longOperation();
store.dispatch({type: “SETDATA”}, payload: data);
return store.dispatch({type: “LOADING”, payload: false});
}
我可以在下一页的 getInitialProps
函数中这样调用它:
MyPage.getInitialProps = async ({ store, isServer }) => {
const loader = takesLong(store)
if (isServer) await loader; // <-- will delay client response
return {
someprop: "some value"
};
};
如果页面在客户端 上加载,此方法效果很好。操作开始,我的页面可以显示加载微调器,直到操作完成。但是当在 服务器端 启动时,我在页面显示之前有很长的延迟。我已经尝试了多种方法,但找不到一种能正常工作的方法:
- 在服务器上启动进程并且不使用
await
呈现页面而没有将结果写入商店,因此它只在商店中将“loading”设置为 true 而它永远不会获取数据. - 在我的
props
中传递store
不起作用 - 它最终成为客户端中的空对象 ({ }
)。 尝试在我的组件中 运行 它似乎不起作用,原因如下:
a) 我在 React 组件中没有可访问的
store
对象(仅在getInitialProps
中不会在客户端调用)。b) 即使我在组件中使用动作而不是
[=50 之前被调用=]store.dispatch
,我什么时候可以安全地调用它?我不能在render
期间执行此操作,因为它会更改 Redux 状态,并且componentWillReceiveProps
不会在第一个客户端render
在使用 Next 时是否有明确定义的模式来将长时间操作推迟到客户端?
在 componentDidMount
上执行长时间的异步任务,它将 运行 仅在客户端执行。
在 SSR 中做出反应,而不是 运行s componentDidMount
生命周期钩子。
在 componentDidMount
期间使用绑定操作有效。感谢@eenagy 的建议。按照这个顺序做事情似乎是在做需要做的事情:
import { bindActionCreators } from "redux";
import { setLoading, setError, setData } from "../actions";
componentDidMount() {
if (!this.props.haveData && !this.props.loading && !this.props.error) {
this.props.setLoading(true);
loadSomeData() // <-- this takes a while to complete
.then( data => {
this.props.setData(data);
this.props.setLoading(false);
})
.catch( err => {
this.props.setError(err);
this.props.setLoading(false);
});
}
}
render() {
if (this.props.loading) return (<Loading/>);
return (/*regular page*/);
}
export const mapDispatchToProps = dispatch => {
return bindActionCreators({ setLoading, setError, setData }, dispatch);
};
export default connect(mapStateToProps, mapDispatchToProps)(Component);
这样,如果初始数据尚未加载(比如由另一个页面加载),它将在 组件挂载和 运行 异步直到操作完成并且 调用 redux 中的操作使页面变为 re-render.