title: Vaadin Dataprovider: how to avoid "auto-fetch"?
body: <p>Use Case 1 is answered below, Use Case 2 has been moved to a separate question (<a href="https://stackoverflow.com/questions/67330474/vaadin-flow-returning-to-a-view-the-view-should-not-reload-data-from-the-backe">Vaadin Flow: Returning to a view, the view should not reload data from the backend</a>)</p>
  <p>I'd like to use a Vaadin Flow (v14 LTS/v19) grid component backed by a lazy <code>DataProvider</code> which does not automatically fetch data from the backend when the grid is shown.</p>
  <p>There are at least two use cases:</p>
  <ul>
  <li>showing grid data does not make sense unless the user provided filter parameters</li>
  <li>returning to a <code>@PreserveOnRefresh</code> tagged view should not replace the shown data with current data. (further elaborated in update)</li>
  </ul>
  <p>Being pretty new to Vaadin 14+, I could not figure out how to achieve this. Every time my <code>GridView</code> is displayed, the count and fetch callbacks of <code>DataProvider</code> are queried. The call originates from the <code>DataCommunicator</code> of the grid.</p>
  <p>So for Use Case 1: How to stop the <code>DataProvider</code> from fetching data as long as it does not make sense?
  And for Use Case 2: How to prevent overwriting the grid state when adding a grid to the UI for the second time?</p>
  <p>Thanks a lot!</p>
  <p>StackTrace to my fetch callback (Vaadin Flow 14):</p>
  <pre><code>        at org.vaadin.example.GridView.fetch(GridView.java:46)
          at org.vaadin.example.GridView.lambda$new$c4b2c115$1(GridView.java:23)
          at com.vaadin.flow.data.provider.CallbackDataProvider.fetchFromBackEnd(CallbackDataProvider.java:137)
          at com.vaadin.flow.data.provider.AbstractBackEndDataProvider.fetch(AbstractBackEndDataProvider.java:61)
          at com.vaadin.flow.data.provider.DataCommunicator.fetchFromProvider(DataCommunicator.java:362)
          at com.vaadin.flow.data.provider.DataCommunicator.activate(DataCommunicator.java:647)
          at com.vaadin.flow.data.provider.DataCommunicator.collectKeysToFlush(DataCommunicator.java:589)
          at com.vaadin.flow.data.provider.DataCommunicator.flush(DataCommunicator.java:461)
          at com.vaadin.flow.data.provider.DataCommunicator.lambda$requestFlush$2f364bb9$1(DataCommunicator.java:425)
          at com.vaadin.flow.internal.StateTree.lambda$runExecutionsBeforeClientResponse$2(StateTree.java:390)
          at [java.util.stream] omitted
          at com.vaadin.flow.internal.StateTree.runExecutionsBeforeClientResponse(StateTree.java:387)
          at com.vaadin.flow.server.communication.UidlWriter.encodeChanges(UidlWriter.java:411)
          at com.vaadin.flow.server.communication.UidlWriter.createUidl(UidlWriter.java:187)
          at com.vaadin.flow.server.communication.UidlRequestHandler.writeUidl(UidlRequestHandler.java:122)
          at com.vaadin.flow.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:91)
          at com.vaadin.flow.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:40)
          at com.vaadin.flow.server.VaadinService.handleRequest(VaadinService.java:1547)
          at com.vaadin.flow.server.VaadinServlet.service(VaadinServlet.java:247)
          at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
  </code></pre>
  <hr />
  <p>update 20210430
  Here's the code of my <code>GridView</code> which also fakes the backend <code>DataProvider</code>:</p>
  <pre><code>@Route(value = &quot;grid&quot;, layout = MainView.class)
  public class GridView extends VerticalLayout {
      public GridView() {
          final Grid&lt;Person&gt; g = new Grid(Person.class);
          g.setColumns(&quot;name&quot;);
          g.setDataProvider(DataProvider.fromCallbacks(q -&gt; fetch(q), q -&gt; count(q)));
          add(g);
          // filter omitted
          final Button refresh = new Button(&quot;refresh&quot;);
          refresh.addClickListener(e -&gt; {
              System.out.println(&quot;refresh clicked&quot;);
              g.getDataProvider().refreshAll();
          });
          add(refresh);
  
          add(new TextField(&quot;State check&quot;));
      }
  
      // fake DataProvider
      private int count(Query&lt;Person, Void&gt; q) { return 3; }
  
      private Stream&lt;Person&gt; fetch(Query&lt;Person, Void&gt; q) {
          q.getLimit(); //vaadin checks these have been called
          q.getOffset(); //vaadin checks these have been called
          System.out.println(&quot;fetching again&quot;);
          new Exception().printStackTrace(); //figure out who called
          return Arrays.asList(new Person(&quot;1&quot;), new Person(&quot;2&quot;), new Person(&quot;3&quot;)).stream();
      }
  }
  </code></pre>
  <p>My <code>MainView</code> is used to switch between <code>GridView</code> and <code>EmptyView</code></p>
  <pre><code>@PreserveOnRefresh
  public class MainView extends AppLayout {
  
      private Component emptyBView;
      private Component gridBView;
  
      public MainView() {
          final Button emptyB = new Button(&quot;Btn empty&quot;);
          emptyB.addClickListener(e -&gt; {
              if (emptyBView == null) { emptyBView = new EmptyView();}
              setContent(emptyBView);
          });
          addToNavbar(emptyB);
  
          final Button gridB = new Button(&quot;Btn grid&quot;);
          gridB.addClickListener(e -&gt; {
              if (gridBView == null) gridBView = new GridView();
              setContent(gridBView);
          });
          addToNavbar(gridB);
      }
  }
  </code></pre>
  <p><code>MainView</code> is an <code>AppLayout</code> used to switch the contents of the <code>AppLayout</code> from <code>GridView</code> to <code>EmptyView</code> and back.</p>
  <p>Use Case 2 is: When returning to <code>GridView</code>, the <code>GridView</code> should be exactly same state as before (which works fine with the <code>TextField</code>).</p>
  <ol>
  <li>open <code>GridView</code> -&gt; grid should not be filled with data</li>
  <li>enter filter params (not shown in code)</li>
  <li>click &quot;refresh&quot; to populate the grid</li>
  <li>enter &quot;Spiderman&quot; in <code>TextField</code> &quot;stateCheck&quot;</li>
  <li>switch to <code>EmptyView</code></li>
  <li>in the real app: do something in <code>EmptyView</code> and potentially other views</li>
  <li>return to <code>GridView</code> -&gt; the grid should <strong>not reload the data</strong>, it should just stay as it was - just like the <code>TextField</code> still displays &quot;Spiderman&quot;, the grid should display the same data as before without reloading it.</li>
  </ol>