Free AI web copilot to create summaries, insights and extended knowledge, download it at here
2989
Abstract
e><p id="dcc0"><code>loadPage</code> takes the current page (we use its <code>endCursor</code> value to specify where the next page starts) and a page size (<code>size</code>), returning the next slice of values and its corresponding <code>PageInfo</code>.</p><p id="099d">In addition to the <code>loadPage</code> function, <code>Pageable</code> also specifies <code>Value</code> as an <code>associatedType</code> conforming to <code>Identifiable</code> and <code>Hashable</code>. The <code>Identifiable</code> and <code>Hashable</code> constraints allow the page’s content to be diffed and easily rendered in a list withinin SwiftUI.</p><h2 id="87cd">Paging View Model</h2><p id="042c">The next part is building our view model for our SwiftUI view. This will encapsulate the following properties:</p><ul><li><code>source</code> (<code>Pageable</code>)</li><li><code>pageSize</code> (number of objects to fetch)</li><li><code>threshold</code> (position of the last object where the next page fetch will be triggered)</li><li><code>pageInfo</code> (details of the current page and next)</li><li><code>state</code> (an enum to hold the the current state of the view model)</li><li><code>items</code> (the source of truth for all our objects)</li></ul>
<figure id="93ee">
<div>
<div>
<iframe class="gist-iframe" src="/gist/LarrrrryT/6ae9a2b73aa35099daf000be1b51bf63.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
</div>
</div>
</figure></iframe></div></div></figure><h2 id="a189">Paging View Model: PagingState</h2><p id="45f9">We also need to know the internal state of the view model to prevent fetching the same page multiple times. We can use an enum to manage the internal state of the paging view model to prevent this.</p>
<figure id="c1ba">
<div>
<div>
<iframe class="gist-iframe" src="/gist/LarrrrryT/4807e29ee0a9abe1e2d0d96eb626272a.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
</div>
</div>
</figure></iframe></div></div></figure><h2 id="14f2">Paging View Model: onAppear</h2><p id="60e8">The next part is defining how our view model fetches the next page from SwiftUI. We first need to know where the user is in the current items array. We can use the <code>onAppear</code> SwiftUI view modifier to notify our view model when an item is currently visible, this will help us understand the position and allow us to kick off a request for the next page if necessary.</p>
<figure id="938f">
<div>
<div>
<iframe class="gist-iframe" src="/gist/LarrrrryT/366c0f27881db58ec855494ffa53a3aa.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
</div>
</div>
</figure></iframe></div></div></figure><
Options
p id="7557">In our view model we define our <code>onItemAppear</code> function with a series of early returns before kicking off a request for the next page.</p>
<figure id="c17c">
<div>
<div>
<iframe class="gist-iframe" src="/gist/LarrrrryT/8d256f514d8c9f4a989c0b83a6115016.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
</div>
</div>
</figure></iframe></div></div></figure><p id="15b6">Let’s break this down:</p><ol><li>We’ve reached the end of the page and can no longer page</li><li>We are currently loading the next or first page</li><li>No index is found</li><li>The index of the our model has not reached our threshold</li><li>Requirements have been met; kick off a request for the next page 🎉</li></ol><h2 id="2230">Paging View Model: loadMoreItems</h2><p id="f1db">Let’s now define our <code>loadMoreItems</code> function.</p>
<figure id="0ab2">
<div>
<div>
<iframe class="gist-iframe" src="/gist/LarrrrryT/3815b3afd2df8f6a7319ecb56fc6c97e.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
</div>
</div>
</figure></iframe></div></div></figure><p id="2e02">Let’s break this down:</p><ol><li>Ask the source for the page given the <code>pageInfo</code> and <code>pageSize</code></li><li>If we’ve set a new <code>currentTask</code> we shouldn’t continue here</li><li>We have our new items set our items based on the state of the view model</li><li>Publish our changes to SwiftUI and reset our state so we fetch the next page if needed</li><li>Publish any errors back to SwiftUI</li></ol><h2 id="4953">Recap</h2><p id="b343">We’ve defined a protocol Pageable that provides a source for our <code>PagingViewModel</code>. Our <code>PagingViewModel</code> gets triggered by the <code>onAppear</code> SwiftUI view modifier. We check the index of the item from the view modifier and determine if the item has met our threshold requirement and if the state is ready to make a page request. Once we have a page response we publish the set of items back into SwiftUI and wait for the next request.</p><p id="55e3">Here is a demo of what that looks like:</p><figure id="de7f"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*X0HI4chSJB4Vef_a8miJaQ.gif"><figcaption></figcaption></figure><h2 id="3dca">Key Takeaways</h2><ul><li><code>Pageable</code> has allowed us to create many sources that can be paged</li><li>updating state to SwiftUI views is as simple as setting a property</li><li><code>PagingState</code> makes our <code>PagingViewModel</code> easy to reason with</li></ul><p id="966b">We’re just getting started on our iOS journey. Interested in building with us?<a href="https://whatnot.com/careers"> We’re hiring</a>!</p><p id="31a7"><i>Special Thanks to Alex Chase and Rami Khalaf</i></p></article></body>