facebook / componentkit

A React-inspired view framework for iOS.
http://www.componentkit.org/
Other
5.76k stars 587 forks source link

Mixing component based views with "regular" view in a UITableview #712

Closed avnerbarr closed 7 years ago

avnerbarr commented 7 years ago

I have existing table view / table view cells etc. using plain UIView layout.

I'm now at the point where I need to add new UI (cells) to the existing list and would like to leverage components for that.

I've read the "dive deeper" documentation regarding UITableView et.al but I'm not clear how I can use my existing table view datasource in tandem with the CKComponentDataSource.

Obviously the indexpaths and "source of truth" aren't the same in this case.

Is there a way to mix and match?

ocrickard commented 7 years ago

Our legacy datasource actually allows certain index paths to be handled by another object. This is the role of the decider: https://github.com/facebook/componentkit/blob/298d700b6a8e5b2ce30a7c2c35f4e4cc40371327/ComponentKit/DataSources/Common/CKComponentDataSource.h#L51

There's growing interest in replicating this behavior in the transactional datasource, since people seem to need it for conversions. For now you can use the legacy datasource.

avnerbarr commented 7 years ago

Is there an example for using this type of datasource?

eczarny commented 7 years ago

There's growing interest in replicating this behavior in the transactional datasource, since people seem to need it for conversions. For now you can use the legacy datasource.

Unfortunately I just removed the deprecated CKComponentDataSource. The decider functionality was purposely lifted out of its replacement, the transactional data source, so it now becomes the responsibility of the UITableView or UICollectionView component data source layer above.

@avnerbarr when using the transactional data source you can mimic the behavior of the decider by implementing a simple fallback mechanism. Internally we do something like this when our collection view requests a cell:

  1. Request the transactional data source for the output item at the request index path
  2. If the component of the output item IS NOT nil a. Mount the component hierarchy as normal
  3. If the component of the output item IS nil a. Request the "fallback cell provider" for a fallback cell with the given data source, collection view, and the current index path b. If a fallback cell IS found return it c. If a fallback cell IS NOT found then mount a nil component (essentially hiding the cell, but keeping it around as a placeholder if a component becomes available a bit later)

To make things a bit easier I can spend some time implementing similar functionality in CKCollectionViewTransactionalDataSource. That way it can either be used out-of-the-box or as an example for those rolling their own component data sources.

avnerbarr commented 7 years ago

Do you have an example I can reference? I'm having problems getting this formula to work.

eczarny commented 7 years ago

@avnerbarr I don't have any specific examples readily available. What problems are you running into?

ocrickard commented 7 years ago

Alright, just to summarize:

  1. CKComponentHostingView is a great way to embed components into a single cell without changing your datasource.
  2. If you can change the datasource of the collection/table view, the fallback cell providing API on the new datasources allow you to vend non-Components cells.
  3. IGListKit is a fantastic way to divide up a collection view into separate sections. You can use https://github.com/ocrickard/IGListKit-ComponentKit to embed a component datasource as a single section in an IGListKit view controller without converting the whole surface.