Почему redux @select не работает, даже если состояние изменяется при использовании redux-state-sync? - PullRequest
1 голос
/ 15 мая 2019

РЕДАКТИРОВАТЬ - Это все работает, если я настраиваю синхронизацию состояний при использовании локального хранилища.Я сделал репозиторий https://bitbucket.org/em-aitch/sync-app/src/master/, который содержит пример рабочего кода.Если тип вещательного канала (app.component.ts: 76) изменяется с 'localalstorage' на 'native', то привязки (и @select, и {{property}} больше не работают!

EDIT2 - Вопрос Как узнать, что нарушает угловое связывание? отвечает на этот вопрос

У меня есть настройка с использованием redux-state-sync , описанной ниже.Изменение состояния избыточности синхронизируется с другим окном браузера, но @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 НЕ появляется. Ниже сначала приведен код, непосредственно связанный с этим, и, в конце концов, определения редукса.

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 Ответ

1 голос
/ 15 мая 2019

Если состояние уже синхронизировано, скорее всего, проблема не в синхронизации с избыточным состоянием, я хотел бы помочь вам решить проблему, однако у меня ограниченные знания Angular и @select.

Но я могу поделиться с вами тем, как работает синхронизация резервных состояний для синхронизации данных на вкладках браузера.

  1. Во время инициализации будут запущены три действия.
const getIniteState = () => ({ type: GET_INIT_STATE });
const sendIniteState = () => ({ type: SEND_INIT_STATE });
const receiveIniteState = state => ({ type: RECEIVE_INIT_STATE, payload: state });

Вкладки, открытые после первой вкладки, будут отправлять действие GET_INIT_STATE в хранилище другой вкладки, как только они получат это действие, они будут отправлять SEND_INIT_STATE вместе с существующим состоянием.В то же время ваша последняя открытая вкладка получит это событие SEND_INIT_STATE вместе со всем состоянием другой вкладки и вызовет RECEIVE_INIT_STATE с состоянием.

По сути, 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);
  });
Все остальные действия, отправляемые из вашего приложения, будут отправляться во все открывающиеся вкладки браузера с точным типом действия и полезной нагрузкой.

Из того, что я вижу, проблема, с которой вы сталкиваетесь, вероятно,наблюдаемое не обнаруживает никаких изменений состояния, поэтому оно не запускает обновление.

Надеюсь, это поможет, извините, что я не смог дать вам больше полезных советов.Дайте мне знать, если вам нужна дополнительная информация от меня, и если вы решили эту проблему, пожалуйста, дайте мне знать.; -)

...