为什么在使用redux-state-sync时即使状态更改了,redux @select也无法工作?

时间:2019-05-15 09:32:38

标签: angular redux angular-redux

编辑-如果我将redux-state-sync配置为使用localstorage,那么这一切都可行。我制作了一个包含工作代码示例的存储库https://bitbucket.org/em-aitch/sync-app/src/master/。如果广播频道类型(app.component.ts:76)从'localstorage'更改为'native',则绑定(@select和{{property}}都不再起作用!

EDIT2-问题How to find out what breaks Angular binding?回答了这个问题

我已使用下面所述的redux-state-sync进行了设置。 Redux状态更改已同步到其他浏览器窗口,但@select不起作用。

当我登录一个窗口时,会出现app-nav-menu,因为ngIf评估为true。同样,两个预订都将写入控制台:

new login state = true                       app.component.ts:20
subsribed to local observable : true         app.component.ts:24

但是,即使在另一个窗口中完成的登录状态更改已在那里同步,其他浏览器窗口也无法以相同的方式工作。控制台输出是相同的:

new login state = true                       app.component.ts:20
subsribed to local observable : true         app.component.ts:24

但是问题是app-nav-menu没有出现。下面首先是与此代码直接相关的代码,最后是redux定义。

app.component.html

<body>
  <app-nav-menu *ngIf="(isLoggedIn | async)"></app-nav-menu>
  <div class="container">
    <router-outlet></router-outlet>
  </div>
</body>

app.component.ts

export class AppComponent {
  title = 'app';
  @select((state: IApplicationState) => state.login.isLoggedIn) isLoggedIn: Observable<boolean>;
  subscription;

  constructor(private ngRedux: NgRedux<IApplicationState>) {
    this.subscription = this.ngRedux.select<ILoginState>('login')
    .subscribe(newState => {
      console.log('new login state = ' + newState.isLoggedIn);
    });

    this.isLoggedIn.subscribe(newState =>
      console.log('subsribed to local observable : ' + newState));
  }
}

app.module.ts

import { createStateSyncMiddleware, initStateWithPrevTab } from 'redux-state-sync';
import { Store, createStore, applyMiddleware } from 'redux';

export const store: Store<IApplicationState> = createStore(
  rootReducer,
  applyMiddleware(createStateSyncMiddleware())
);

export class AppModule {
  constructor(ngRedux: NgRedux<any>) {
    ngRedux.provideStore(store);
    initStateWithPrevTab(store);
  }
}

store / index.ts

import { combineReducers  } from 'redux'
import { ILoginState, loginReducer } from './login'
import { withReduxStateSync } from 'redux-state-sync'

export interface IApplicationState {
  login: ILoginState;
}

export const INITIAL_STATE : IApplicationState = {
   login : { isLoggedIn: false, tokenInfo : null } 
}

const appReducer = combineReducers<IApplicationState>({
  login: loginReducer
})

export const rootReducer = withReduxStateSync(appReducer);

就像我在顶部的编辑中说的那样。如果我将其配置为使用localstorage,则此方法有效:

applyMiddleware(createStateSyncMiddleware( 
  { broadcastChannelOption: { type: 'localstorage' } })));

1 个答案:

答案 0 :(得分:1)

如果状态已经同步,则可能不是redux-state-sync问题,我想帮助您解决问题,但是,我对Angular和@select的了解有限。

但是我可以与您分享Redux-state-sync如何在浏览器标签之间同步数据。

  1. 初始化期间将触发三个动作。
const getIniteState = () => ({ type: GET_INIT_STATE });
const sendIniteState = () => ({ type: SEND_INIT_STATE });
const receiveIniteState = state => ({ type: RECEIVE_INIT_STATE, payload: state });
  1. 在第一个选项卡之后打开的选项卡会将GET_INIT_STATE操作分派到另一个选项卡的存储中,一旦他们收到此操作,它们将分派SEND_INIT_STATE以及现有状态。同时,您最后打开的标签页会收到此SEND_INIT_STATE事件以及其他标签页的整个状态,并使用该状态触发RECEIVE_INIT_STATE。

  2. 基本上,withReduxStateSync将侦听RECEIVE_INIT_STATE操作,并将整个状态替换为该操作的有效负载。

export const withReduxStateSync = appReducer =>
  ((state, action) => {
    let initState = state;
    if (action.type === RECEIVE_INIT_STATE) {
      initState = action.payload;
    }
    return appReducer(initState, action);
  });
  1. 从您的应用程序分派的所有其他操作将在所有打开的浏览器标签中分派,并带有确切的操作类型和有效负载。

据我所见,您面临的问题可能是可观察到的问题,即未检测到状态的任何变化,因此不会触发更新。

希望这会有所帮助,对不起,我无法为您提供更多有用的建议。如果您需要我提供更多信息,请告诉我,如果您解决了此问题,也请告诉我。 ;-)