我正在尝试使用rxjs obserable包装器在redux应用程序中使用redux状态存储。 Source tutorial
当我从角度切换到nxx到redux时,我首先尝试了这种方法。现在我在反应应用程序中使用此模式。但是,我有点问题。当我订阅一些状态存储流时,我使用setState(foo)
将值存储在组件中。这反过来会触发一个新的渲染周期。我希望每个组件有一个渲染周期而不是2个或更多。
我一直在尝试禁止组件的初始呈现,以便首先触发它,并且只通过状态存储订阅触发一次。当您有多个嵌套组件和多个订阅时,它们往往会创建浪费的渲染,只是为了执行app init。我知道React在优化多个渲染方面做得很好,但我仍然发现,关注渲染周期对于避免细微的错误是健康的。
有关如何从州商店订阅触发第一次呈现的任何建议吗?
app.module.tsx
private subscribeToAppSettings() {
DEBUG.cmp && debug('Subscribe appSettings$');
appSettings$().pipe(
skip(1), // For REST api calls I skip the initial state
takeUntil(this.destroyed$),
)
.subscribe(settings => {
DEBUG.subscribe && debug('==> Observe appSettings$', [settings]);
this.setState({ settings });
});
}
正如您所看到的那样,AppModule
和其他所有内容都会被渲染两次。这是一组经过筛选的日志,在应用程序运行render()
方法时展示。只是初始阶段,没有用户交互。
答案 0 :(得分:0)
在再次审查整个架构之后,我想我需要在组件中手动设置初始状态。现在,初始渲染正在进行有用的工作,第二次渲染将被反应变化检测忽略。
我还有额外的渲染周期。但是,我看到这是变化检测的状态。很多事情都会触发第二次渲染:init,路由器,事件处理程序,observables。只要React使用虚拟dom进行变更检测来清除实际没有变化的值,就不应该对性能产生实际影响。正如他们所说:我在错误的树上吠叫。
<强> state.service.tsx 强>
{
"access_token" : "myAccessToken",
"token_type" : "bearer",
"expires_in" : 3600,
"refresh_token" : "myRefreshToken",
"refresh_token_expires_in" : 604800,
"scope" : "Meetings VoipCalling Glip SubscriptionWebhook Faxes Contacts RingOut SMS",
"owner_id" : "11111111",
"endpoint_id" : "22222222"
}
<强> app.module.tsx 强>
/** Access state changes as an observable stream */
export const store$ = new Observable<AppState>(observer => {
// All state store observable use `distinctUntilChanged()` operator.
// Without this initial state, `distinctUntilChanged()` will be unable to compare previous and current state.
// As a result, the webapi observable will miss the first response fron the server.
observer.next(appInitialState);
let appState: AppState;
store.subscribe( () => {
appState = store.getState();
observer.next(appState);
});
})
<强> search.overlay.smart.tsx 强>
constructor(props: any) {
super(props);
DEBUG.construct && debug('Construct AppModule');
this.state = {
navigatorIsVisible: appInitialState.navigator.isVisible,
searchOverlayIsVisible: appInitialState.search.isVisible
} as State;
getAppSettings();
}
<强> search.overlay.service.tsx 强>
searchOverlayIsVisible$().pipe(
takeUntil(this.destroyed$),
skip(1), // Ignore init state
)
.subscribe(searchOverlayIsVisible => {
DEBUG.subscribe && debug('Observe searchOverlayVisiblity$', searchOverlayIsVisible);
this.setState({ searchOverlayIsVisible });
this.state.searchOverlayIsVisible
});
<强>结论强>
export function toggleSearchOverlay(isVisible?: boolean) {
if (DEBUG.service && DEBUG.verbose) debug('Toggle search overlay', isVisible);
store.dispatch(
searchActions.toggleSearch(isVisible)
);
return searchOverlayIsVisible$();
}
export const searchOverlayIsVisible$ = () => store$.pipe(
map( state => SEARCH_VISIBILITY(state) ),
distinctUntilChanged()
);
observable中推送初始状态是必要的,因为我们需要所有状态存储可观察量来接收它们的第一个状态。如果没有此初始状态store$
将无法运行先前和当前状态之间的比较。如果distinctUntilChanged()
阻止了可见的内容,那么我们最终会阻止来自webapi的响应。这意味着即使状态存储收到第一组数据,我们也会看到空页。distictUntilChanged
将禁止第二次渲染。 skip(1)
操作都需要初始状态才能开始。 TOGGLE
中每次路线更改只有一次componentDidUpdate
次呼叫几乎不可能。这意味着我们仍需要过滤掉对LessonsPage
的重复调用。