Vaadin Flow: возвращаясь к представлению, представление не должно перезагружать данные из бэкэнда.

Отделить от Vaadin Dataprovider: как избежать автоматической загрузки?.

Для приложения Vaadin Flow 19 с MainView extends AppLayout, GridView и EmptyView
и @PreserveOnRefresh аннотация используется на MainView.

При возврате в GridView GridView должен быть точно в том же состоянии, что и раньше:

  1. открыть GridView с помощью кнопки в MainView впервые - ›Grid использует DataProvider для извлечения данных из серверной части
  2. введите "Человек-паук" в TextField с подписью "СостояниеПроверьте"
  3. переключиться на EmptyView с помощью кнопки в MainView
  4. в реальном приложении: сделайте что-нибудь в EmptyView и, возможно, в других представлениях
  5. вернуться к GridView с помощью кнопки в MainView второй раз

Затем (1) TextField с заголовком stateCheck должен отображать значение Spiderman
и (2) сетка должна по-прежнему отображать те же данные, что и раньше; он не должен перезагружать данные из серверной части

Наблюдаемое поведение: (1) нормально, но (2) нет: сетка всегда вызывает fetch метод для получения данных из серверной части.

Как добиться желаемого поведения?


Вот код моего GridView, который также подделывает серверную часть DataProvider:

@Route(value = "grid", layout = MainView.class)
public class GridView extends VerticalLayout {
    public GridView() {
        final Grid<Person> g = new Grid(Person.class);
        g.setColumns("name");
        g.setDataProvider(DataProvider.fromCallbacks(q -> fetch(q), q -> count(q)));
        add(g);

        add(new TextField("State check"));
    }

    // fake DataProvider
    private int count(Query<Person, Void> q) { return 3; }

    private Stream<Person> fetch(Query<Person, Void> q) {
        q.getLimit(); //vaadin checks these have been called
        q.getOffset(); //vaadin checks these have been called
        System.out.println("fetching again");
        return Arrays.asList(new Person("1"), new Person("2"), new Person("3")).stream();
    }
}

MainView используется для переключения между GridView и EmptyView

@PreserveOnRefresh
public class MainView extends AppLayout {

    private Component emptyBView;
    private Component gridBView;

    public MainView() {
        final Button emptyB = new Button("Btn empty");
        emptyB.addClickListener(e -> {
            if (emptyBView == null) { emptyBView = new EmptyView();}
            setContent(emptyBView);
        });
        addToNavbar(emptyB);

        final Button gridB = new Button("Btn grid");
        gridB.addClickListener(e -> {
            if (gridBView == null) gridBView = new GridView();
            setContent(gridBView);
        });
        addToNavbar(gridB);
    }
}

person sk_dev    schedule 30.04.2021    source источник
comment
Боковое примечание: @PreserveOnRefresh предназначен для использования в представлениях с @Route. В вашем случае вы не используете маршрутизатор для навигации, а просто вручную переключаете компоненты. Проблема, связанная с вызовом DataProvider при повторном подключении представления, может быть ошибкой.   -  person Marcus Hellberg    schedule 30.04.2021
comment
На самом деле это намеренное поведение. Прослушиватель провайдера данных на стороне сервера необходимо удалить при отсоединении компонента и перенастроить его при присоединении. Причина в том, что в противном случае слушатели будут накапливать и производить утечку памяти.   -  person Tatu Lund    schedule 30.04.2021
comment
@MarcusHellberg Я знаю, есть еще одна (теперь решенная) проблема с @Route, которая привела к этому примеру кода - спасибо   -  person sk_dev    schedule 03.05.2021


Ответы (1)


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

Теперь можно было бы развлечься идеей иметь такого рода кеширование ранее загруженных данных через API в Grid также в структуре Vaadin, поскольку это может быть или нежелательно. Это зависит от приложения.

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

Если вы хотите избежать дополнительной бомбардировки БД, поскольку известно, что данные статичны, вам нужно иметь кеширование.

person Tatu Lund    schedule 30.04.2021
comment
Предположим, что следующий вариант использования 1. Откройте сетку статей, отфильтруйте и выберите статью 4711 2. Начните редактировать статью 4711 на панели подробностей сетки статей 3. Переключитесь в другое представление, чтобы найти значение 4. Вернитесь в сетку статей, чтобы продолжить редактирование article 4711 5. Сохранить статью 4711 В этом случае пользователь не хочет перезагружать сетку статей на шаге 4. - person sk_dev; 03.05.2021
comment
Я не говорю об обновлении страницы. Это просто возврат к ранее открытому виду. Это просто то, что вы называете кешированием: Храните данные сетки до тех пор, пока пользователь явно не решит (повторно) загрузить данные из серверной части. Причина в том, чтобы отображать согласованные данные (не избегая обратных обращений к серверу). Итак, вы говорите, что это кеширование необходимо реализовать в приложении, поскольку Vaadin не поддерживает его из коробки? У тебя есть какие-нибудь подсказки, с чего начать? - person sk_dev; 03.05.2021
comment
@sk_dev У вас есть какие-нибудь подсказки, с чего начать? ehcache - довольно популярное решение для внутреннего кэширования ehcache.org - person Tatu Lund; 03.05.2021
comment
мой вопрос был больше направлен на vaadin :-). Я думал о Clientside / DataProvider или лучшем сервере (backend) ... но я думаю, что это вопрос архитектуры, который мне нужно обсудить в команде. Спасибо пока - person sk_dev; 03.05.2021