Copy of View
An entity that accepts a collection of properties and returns an element.
Definition
As opposed to a Function, the property order for views doesn't matter, it always produces the same type signature. The only valid return types for a view are the Primitives.
view SimpleView(age: number, name: string) -> {
<div />
}
// is equivalent to
view AlternateView(name: string, age: number) -> {
<div />
}
// and
type SpreadType {
age: number;
name: string;
}
view SpreadView(...props: SpreadType) -> {
<div />
}
SimpleView.Props; // $Type(age: number, name: string)
AlternateView.Props; // $Type(age: number, name: string)
SpreadView.Props; // SpreadType -> $Type(age: number, name: string)
SimpleView;
// $View<SimpleView.Props, SimpleView()>
// -> $View<$Type(age: number, name: string), SimpleView()>
AlternateView;
// $View<AlternateView.Props, AlternateView()>
// -> $View<$Type(age: number, name: string), AlternateView()>
SpreadView;
// $View<SpreadView.Props, SpreadView()>
// -> $View<SpreadType, SpreadView()>
// -> $View<$Type(age: number, name: string), SpreadView()>Keys
In order to differentiate elements for more efficient re-rendering, keys can be provided (this might not actually be necessary based on how we build the dependency graphs).
view ListView(items: string[]) -> {
<ul class="list">
{items.map((item, index) => {
<li({index}) class="list__item">
<span>{item}</span>
</li>
}}
</ul>
}Omit Parentheses
When your view does not accept properties, the parentheses can be omitted.
view SimpleView() -> { /* ... */ } // not preferred
view SimpleView -> { /* ... */ } // preferredView Composition
Building your view's with composition in mind allows you to re-use them easily and combine them with other view's to create complex experiences for your users with ease.
Slots
Composition is achieved by using special <slot> tags to inject content placed within the containing view. This allows view's to be more easily re-used, such as a complex "button" that can have different textual content injected into it.
view WrappingView -> {
<div class="wrapper">
<slot />
</div>
}
view ComposingView -> {
<h1>
<WrappingView>
<span>Inner Content</span>
</WrappingView>
</h1>
}
// generates the following HTML
// <h1>
// <div class="wrapper">
// <span>Inner Content</span>
// </div>
// </h1>Named Slots
In order to inject multiple different pieces of content, slots can be named and matched to the keys provided on elements placed into the view.
view ModalView {
<div class="modal">
<h1 class="modal__header">
<slot(header) />
</h1>
<div class="modal__body">
<slot(body) />
<div>
<div class="modal__footer">
<slot(footer) />
<div>
</div>
}
view AlertModal {
<Modal>
<span(header)>This is a modal</span>
<div(body)>
<p>some content...</p>
<p>some more content...</p>
</div>
<div(footer)>
<button>Cancel</button>
<button>OK</button>
</div>
</Modal>
}
// generates the following HTML
// <div class="modal">
// <h1 class="modal__header">
// <span>This is a modal</span>
// </h1>
// <div class="modal__body">
// <div>
// <p>some content...</p>
// <p>some more content...</p>
// </div>
// <div>
// <div class="modal__footer">
// <div>
// <button>Cancel</button>
// <button>OK</button>
// </div>
// <div>
// <div>
// </div>
// </div>Default Content
Slots can be provided with default content that is replaced if overridden by the containing view.
view NamedSlotView -> {
<div class="named-slot">
<slot(optional)>
<span>some default content</span>
</slot>
<div>
}
view NonComposingView -> {
<NamedSlotView />
}
view ComposingView -> {
<NamedSlotView>
<h1>overridden content</h1>
</NamedSlotView>
}
// generates the following HTML
// <div class="named-slot">
// <span>some default content</span>
// </div>
// generates the following HTML
// <div class="named-slot">
// <h1>overridden content</h1>
// </div>Alternate Composition
The above solution might not be so good because it ties you more closely to only being able to use the children in a very rigid way. This alternative pattern sticks closer to React's children.
Slots
The keyword children is available within any view to easily access the children placed into it.
view WrappingView -> {
<div class="wrapper">
{children}
</div>
}
view ComposingView -> {
<h1>
<WrappingView>
<span>Inner Content</span>
</WrappingView>
</h1>
}
// generates the following HTML
// <h1>
// <div class="wrapper">
// <span>Inner Content</span>
// </div>
// </h1>Named Slots
In order to inject multiple different pieces of content, children can be selected based on their keys.
view ModalView -> {
<div class="modal">
<h1 class="modal__header">
{children.header}
</h1>
<div class="modal__body">
{children.body}
<div>
<div class="modal__footer">
{children.footer}
<div>
</div>
}
view AlertModal -> {
<Modal>
<span(header)>This is a modal</span>
<div(body)>
<p>some content...</p>
<p>some more content...</p>
</div>
<div(footer)>
<button>Cancel</button>
<button>OK</button>
</div>
</Modal>
}
// generates the following HTML
// <div class="modal">
// <h1 class="modal__header">
// <span>This is a modal</span>
// </h1>
// <div class="modal__body">
// <div>
// <p>some content...</p>
// <p>some more content...</p>
// </div>
// <div>
// <div class="modal__footer">
// <div>
// <button>Cancel</button>
// <button>OK</button>
// </div>
// <div>
// </div>Extend or Implement Other Views
Override or extend the signature and functionality of another view.
view BaseView(x: string, y: string) -> {
<div>You are the {x} to my {y}</div>
}Property Type Inheritance
Properties by the same name as the super view inherit the same types by default.
view CopyView(x, y) : BaseView -> {
x; // string
y; // string
}Simple Property Transformation
Easily transform properties before applying them to a base view.
view SimpleExtendingView(x, y) : BaseView(x: `x: {x}`, y);Partially Apply Properties
Properties can be applied during view declaration. If no properties are passed to the extended view, the parentheses can be omitted.
view PartialApplicationExtendingView(x, y) : BaseView(x) -> {
super(y: `my value {y}`)
}
// or without partial application
view NoPartialApplicationExtendingView(x, y) : BaseView -> {
let formatted = `my value {y}`;
super(x, y: formatted);
}Extend and Augment Signature
Override and the property signature of the extended view.
view AugmentedExtendingView(x, y: number, z: string) : BaseView -> {
let formatted = `my value {y} with {z}`;
super(x, y: formatted);
}
AugmentedExtendingView.Props; // $Type(x: string, y: number, z: string)Extension as an Interface
Use extend another view for its signature.
view InterfacingView(x, y) : BaseView -> {
<span>Some other {x} of {y}</span>
}Nest Super Content
Nest content from super view inside of more tags.
view NestedExtendingView(x, y) : BaseView(x, y) -> {
<h1 id="nested">
{super()}
</h1>
}Full view declaration syntax
NOTE: consider an alternative to
withsuch as the&character.
view ComplexView(a, b, c) : BaseView(a, b) ~ SomeState, OtherState(), SomeProvider, OtherProvider(c) -> {
}Create State explicitly (bypass dependency injection)
Ignore grabbing a state from the currect scope by partially or fully constructing one in the declaration of the view.
state MyState(y: string, x: number) -> { }
// force a local state while receiving parameters from a provider / multiple partial application providers
view SomeView ~ MyState() -> { }
view PartialConstructionView ~ MyState#(x: 2) -> { }
view PartialConstructionView ~ MyState('abc') -> { }Partial Context Application
state ValueProvider($x: number, $y: number) -> { }
view TopLevel -> {
<ValueProvider x={123}>
<div>
<ChildComponent />
</div>
</ValueProvider>
}
view ChildComponent -> {
<ValueProvider y={657}>
<span>
<DependentComponent />
</span>
</ValueProvider>
}
view DependentComponent ~ ValueProvider {
<div>
<span>x: {$x}</span>
<span>y: {$y}</span>
</div>
}Last updated
Was this helpful?