1

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

EDIT2 - 问题如何找出破坏 Angular 绑定的原因?回答这个问题

我已经使用下面描述的 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);
  }
}

存储/索引.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);

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

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

1 回答 1

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. 从您的应用程序分派的所有其他操作将在所有打开的浏览器选项卡中分派,并具有确切的操作类型和有效负载。

据我所知,您面临的问题可能是 observable 没有检测到状态的任何更改,因此它不会触发更新。

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

于 2019-05-15T15:10:22.890 回答