-
Notifications
You must be signed in to change notification settings - Fork 3
Taking control of a component's lifecycle within a list
The simplest way to define a component type within a list is to provide a component function, as the examples above demonstrate. You then supply a preconstructed sources
object which the collection will use when it instantiates the component. Sometimes, however, you need a little more control over how components are instantiated and managed. When defining a component, rather than passing the component function directly, you can provide a component type definition object.
First let's look at how a collection works by default.
When you ask the collection to add a new item, the collection needs to actually instantiate the component first. So this operation:
const newList = list.add(someType, sourcesToUse);
... actually results in the following:
(1) The collection locates the type definition matching the specified type id. A type definition has the following basic signature. If you only provided a component function when defining the collection, the collection creates a definition for you and fills in the blanks:
type ComponentType: {
sources?: Sources
key: ComponentTypeIdentifier
fn?: ComponentFunction
instantiate?: (input: Input, type: TypeDefinition, list: ICollection) => Sinks
}
All of these can be overridden with custom values as needed.
(2) Once it has located the type definition, it calls the type's instantiate
function, passing in the input you provided (which has always been a sources
object in the examples up until this point), as well as the type definition and a reference to the collection itself. The default instantiate
implementation creates a new sources object by merging the item input (if it appears to be a sources object) into the default sources for the type definition (if present) and then merges that into the collection's default sources object (again, if present). This means you can supply default sources at both the collection level and the component type level and then only worry about supplying the additional source streams that are specific to the object, such as a props$
stream. The default instantiate
function then calls the component function (the fn
property of the type definition), passing it the new sources object, and then returns the result.
Overriding the instantiate
function with your own implementation gives you complete control over how list inputs are handled in the process of instantiating a component. While the default implementation treats inputs as sources, your own implementation can make any assumption it wants, allowing you to provide other types of inputs such as props or just simply pure data.
A custom type definition with your own instantiate
function might look like so:
function emitVideoProps(video) {
return most.just(video);
}
const emptyList = Collection({
types: [{
key: 'video',
instantiate: (video, type, list) => {
const sources = {
...list.sources,
...type.sources,
props$: emitVideoProps(video)
};
return VideoComponent(sources);
}
}]
});
// And then:
const newList = emptyList.add('video', {title: 'To Kill A Mockingbird', year: 1962});
Notice that the fn
property has been omitted, as the custom instantiate
function calls the component function directly. The reason you normally need to specify the component function when defining a type is because otherwise the Collection
instance won't know how to create your sinks when you pass it a new input, and the default implementation of the instantiate
function looks for the fn
property.
Naturally you could also do the equivalent of the above example, but via the define
function.
- [Managing child components](Managing child components)
- [Replacing a child component when state changes](Replacing a child component when state changes)
- [Combining multiple sinks from child components](Combining multiple sinks from child components)
- [Simple merging of a common sink to a derivative stream](Simple merging of a common sink to a derivative stream)
- [Dynamic lists of child components](Dynamic lists of child components)
- [Managing lists of components that don't have a key](Managing lists of components that don't have a key)
- [Handling multiple component types in a single list](Handling multiple component types in a single list)
- [Taking control of a component's lifecycle within a list](Taking control of a component's lifecycle within a list)
API Reference
- [Quick Reference](API Quick Reference)
- [Detailed Reference](API Detailed Reference)