Рендеринг компонента запуска триггера из наблюдаемой подписки rxjs (пропустите начальный рендер) - PullRequest
0 голосов
/ 03 мая 2018

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

Я впервые попробовал этот подход, когда переключился с ngrx на redux в angular. Теперь я использую этот шаблон в приложении реакции. Тем не менее, у меня есть небольшая проблема. Когда я подписываюсь на некоторый поток хранилища состояний, я использую setState(foo) для хранения значения в компоненте. Это, в свою очередь, запускает новый цикл рендеринга. Я хотел бы иметь один цикл рендеринга на компонент вместо 2 или более.

Я пытался запретить начальный рендеринг компонента, чтобы он запускался первым и только один раз по подписке хранилища состояний. Когда у вас есть несколько вложенных компонентов и несколько подписок, они имеют тенденцию создавать расточительные визуализации только для инициализации приложения. Я знаю, что 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(). Просто этап инициализации, без взаимодействия с пользователем.

enter image description here

1 Ответ

0 голосов
/ 04 мая 2018

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

У меня все еще есть дополнительные циклы рендеринга. Тем не менее, я вижу, что это положение дел с обнаружением изменений. Многие вещи запускают второй рендеринг: инициализация, маршрутизатор, обработчики событий, наблюдаемые. Пока React использует виртуальный домен для обнаружения изменений, чтобы отсеять значения, которые на самом деле не меняются, реального влияния на производительность не должно быть. Как говорится: я лаю не на том дереве.

state.service.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);
    });

})

app.module.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.smart.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
    });

search.overlay.service.tsx

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()
);

Выводы

  • Выдвижение начального состояния в наблюдаемую store$ необходимо, потому что нам нужны все наблюдаемые в хранилище состояний, чтобы получить их первое состояние. Без этого начального состояния distinctUntilChanged() не сможет выполнить сравнение между предыдущим и текущим состоянием. Если distictUntilChanged блокирует обозримые объекты, то мы в конечном итоге блокируем ответы от webapi. Это означает, что мы видим пустые страницы, даже если хранилище состояния получило первый набор данных.
  • Обратите внимание, что мы используем конструктор компонента для настройки начального состояния. Таким образом, мы используем первый цикл рендеринга для полезной работы. Второй рендеринг будет запрещен путем использования skip(1) во всех наблюдаемых хранилищах состояний.
  • Даже если мы устанавливаем состояние инициализации в конструкторе, мы все равно сохраняем исходное состояние и в редукторах. Все действия TOGGLE должны начинаться с начального состояния.
  • Имейте в виду, что многие процессы запускают второй рендеринг: init, маршрутизатор, обработчики событий, наблюдаемые. Пока React использует виртуальный dom для обнаружения изменений, чтобы отсеять значения, которые на самом деле не меняются, никакого реального влияния на производительность рендеринга DOM не должно быть.
  • Это означает, что почти невозможно сделать только один componentDidUpdate вызов на изменение маршрута в LessonsPage. Это означает, что нам все еще нужно отфильтровать повторяющиеся вызовы на handlRouteParams().
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...