Documentation

Report Edit

Private Store

import { PrivateStore } from 'cx/widgets';

PrivateStore allows a part of the widget tree to work with a separate data store, isolated from the global store. This way multiple components can use the same bindings that can have different values betwen the stores.

In the example below, each Slider is storing its value under the same binding (slider). But each slider binding can have a different value within its own data store. You can test this by moving the sliders. Sliders that are within the same PrivateStore will show the same values.

 
 
 
 
 
 
Widget
<div class="widgets">  
    <div class="flex-column">
        <Slider value-bind="slider" label="Global store" />
        <Slider value-bind="slider" label="Global store" />
    </div>
    <PrivateStore>
        <div class="flex-column">
            <Slider value-bind="slider" label="Private store A" />
            <Slider value-bind="slider" label="Private store A" />
        </div> 
    </PrivateStore>
    <PrivateStore>
        <div class="flex-column">
            <Slider value-bind="slider" label="Private store B" />
            <Slider value-bind="slider" label="Private store B" />
        </div> 
    </PrivateStore>
</div>
Copied!Cx Fiddle

Private stores have the lifespan of the PrivateStore component, meaning each time a PrivateStore component is destroyed, the data is lost. This can be observed if you move the sliders, navigate to another page and come back again. Only the sliders within the global store will be in the same position as before, while the others will be in their starting positions.

Sharing data between the stores

Data shared between the parent (in this case global) store and the child store must be explicitly defined with the data property. data is an object whose property names represent the internal bindings under which the property values are made available within the PrivateStore. In the example below, slider binding from the global store is available as globalValue binding within the PrivateStore.

Global store
 
Private store
 
 
Widget
<div class="widgets flex-row flex-start">  
    <div class="flex-column">
        <strong>Global store</strong>
        <Slider value-bind="slider" label="Global value" />
    </div>
    <PrivateStore
        data={{
            globalValue: { bind: "slider" },
        }}
    >
        <div class="flex-column">
            <strong>Private store</strong>
            <Slider value-bind="globalValue" label="Global value" />
            <Slider value-bind="slider" label="Private value" />
        </div> 
    </PrivateStore>
</div>
Copied!Cx Fiddle

Property values can be primitives, bindings, expressions or computables.

Read-only values

Primitives, expressions and computables defined in the data object are treated as read-only. This means, data will flow only in one direction, from parent to child store. You can test this by trying to move one of the sliders within the PrivateStore.

Global store
 
Private store
 
 
 
Index
<div class="widgets flex-row flex-start">  
    <div class="flex-column">
        <strong>Global store</strong>
        <Slider value-bind="slider" label="Global value" />
    </div>
    <PrivateStore
        data={{
            // read-only values
            globalValueExpr: { expr: "{slider}" },
            primitiveValue: 33,
            computedValue: computable("slider", (slider) => 100 - slider)
        }}
    >
        <div class="flex-column">
            <strong>Private store</strong>
            <Slider value-bind="globalValueExpr" label="Global value" />
            <Slider value-bind="primitiveValue" label="Primitive value" />
            <Slider value-bind="computedValue" label="Computed value" />
        </div> 
    </PrivateStore>
</div>
Copied!Cx Fiddle

Attempting to change PrivateStore's read-only values will log an error to the console, so the UI should prevent it.

Performance improvements

PrivateStore can also be used for performance improvements since it supports some advanced features such as deferred rendering and seperate (detached) render loop.

Detached render loop

If detached attribute is used, PrivateStore content is rendered in its own render loop. A data declaration is used to determine which changes can go in or out. This means private data changes will not cause the main render loop to run, and vice versa, any change of global data that is not used within PrivateStore will not cause its subtree to re-render. This can be observed with the use of React Developer Tools, by enabling the Highlight Updates feature.

In most cases you should use this feature, as it can significantly improve performance. Be aware however that it may break some advanced Cx features that depend on the use of shared context. A typical example where this occures is with the use of layouts.

Deferred rendering

By using deferredUntilIdle flag, we can defer the render of the PrivateStore's subtree for a certain time limit (idleTimeout), or until the browser is idle. This can be very useful, for example, when loading a page with a lot of heavy content, so it helps breaking it up into smaller chunks the browser can defer rendering until idle, or the user is inactive. In the background, deferredUntilIdle uses requestIdleCallback API.

Configuration

PropertyDescriptionType
data

Object whose property names represent the internal bindings under which the property values are available within the PrivateStore.

object
deferredUntilIdle

Improves performance by deferring the render until the browser is idle.

boolean
detached

Improve performance by detaching PrivateStore subtree from the rest of the page. Detached content renders in its own render loop and uses a data declaration to determine which changes can go in or out. Detached render loops break the use of context, so some advanced Cx features, such as layouts, may not work.

boolean
idleTimeout

Time limit in milliseconds a browser can defer the render.

number
immediate

Set to true to disable batching of updates.

boolean
items
children

List of child elements.

array
layout

Define an inner layout.

string/object
mod

Appearance modifier. For example, mod="big" will add the CSS class .cxm-big to the block element.

string/array
outerLayout

Defines the outer layout which wraps the widget.

widget
plainText

Set to true to avoid converting inner strings to templates. Default is false.

boolean
preserveWhitespace
ws

Keep whitespace in text based children. Default is false. See also trimWhitespace.

boolean
putInto
contentFor

Used with outer layouts. Specifies the name of the content placeholder which should render the widget.

string
trimWhitespace

Remove all whitespace in text based children. Default is true. See also preserveWhitespace.

boolean
vdomKey

Key that will be used as the key when rendering the React component.

string
visible
if

Visibility of the widget. Defaults to true.

boolean