Skip to content
This repository has been archived by the owner on Jan 14, 2020. It is now read-only.

Demo using React Native with IGListKit to create a JavaScript driven UICollectionView

Notifications You must be signed in to change notification settings

eliperkins/react-native-listkit

Repository files navigation

React Native + IGListKit = UICollectionViews with React-rendered cells at 60fps

⚠️ Work in progress... ⚠️

A glorious gif of nested UICollectionViews with React Native-powered cells scrolling at 60fps

Getting Started

  • yarn install
  • cd ios
  • carthage bootstrap --platform ios
  • open RNListKit.xcodeproj
  • Build and run

🤔 What is this thing?

This demonstrates how we're using IGListKit in our React Native app at Clubhouse.

This project rips out the interesting bits of combining these two technologies, sans our domain-/product-specific bits.

We opened the source of this project up to ask the IGListKit community some questions, file an Apple TSI for some drag-and-drop bugs we've seen, and generally show the iOS and React Native communities how to make great platform-specfic experiences with these technologies!

😐 But... why?

We wanted to build an experience for our Stories view that allowed users to drag-and-drop Stories between columns, within a column, and even outside of the app, into other apps. To do this, we would need to implement some new APIs introduced in iOS 11. While projects like Matt Oakes' react-native-ios-drag-drop exist to bind to UIDragItems from JS-land, we wanted to go even further and use a UICollectionView to allow our users to drag-and-drop across iOS.

Another goal of ours was to keep as much of our view layer in React Native land as possible, in order to prevent duplicating code or features in ObjC/Swift and JavaScript. We didn't want to create a StoryView.swift when we were already using a <StoryView /> throughout our app in many places.

🤨 Okay, but why IGListKit and not just UICollectionView?

We spent some time trying to do this without the help of IGListKit, but quickly realized that there are a lot of niceities that IGListKit would bring to us here! A few main ones were:

Simplified layout of cells, as they relate to their props (including caching of cell sizes)

IGListKit shares some paradigms with React's render model: Given the same data in, I'll give you a view out that matches your expectations

Decoupling of UICollectionView concepts from complex view layouts

It was really easy to create a nested UICollectionView inside a UICollectionView to give us mutiple scrollable columns to drag items to the right spot. A single UICollectionView and layout wouldn't be able to give us this, and ballooning this out into multiple UICollectionViews without IGListKit made our data flow hard to manage

A nice abstraction around the layout we wanted, without coupling our data model

We could create abstract concepts, like Section and Item in IGListKit-land, and then populate the data needed to render our product-specific views on the native side, while our JS abstraction could handle all the bits it needed to know about.

😖 IGListKit Caveats

This wasn't without it's caveats, however. A few pain points we ran into with IGListKit were:

The documentation isn't completely straight-forward

Since we didn't have all our data modeled nicely in Swift like the IGListKit docs kind of recommend, we had to dive in and figure out what models to draw up to get to a place we liked. Our first attempt was riddled with bugs related to a new set of data coming in from JS, that would do things like reset scroll state, or crash on pagination due to an invalid number of insertions/deletions. We set out to try to understand how IGListBindingSectionController could help us, since we knew it could help us do the diffing along with inserts and deletes

However, even now, with this demo project done, I'm not entirely sure of the repercussions of using new value types vs new reference types for ListDiffable implementations, or what the cost of creating new view models during pagination is instead of mutating an existing view model. I'd love some more clarity here (PRs gladly accepted)!

Another hurdle we ran into is understanding when and were to create adapters, and their relationships with view models and even UIViewController itself.

TODO

This is still a work-in-progress, as we still product code into this sample project

  • Add drag-and-drop to reorder functionality
  • Dynamic cell heights given a React Native view's intrinsic content size
  • Proper loading states
  • Turn into a proper React Native node_module, consumable via react-native link (I see you @neilkimmett)
  • Fabric for UICollectionViewCells?!

About

Demo using React Native with IGListKit to create a JavaScript driven UICollectionView

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published