ParcelBoundary

ParcelBoundary is a React component. It’s job is to optimise rendering performance, and to optionally control the flow of parcel changes.

Each ParcelBoundary is passed a Parcel. By default the ParcelBoundary uses pure rendering, and will only update when the Parcel’s data changes to avoid unnecessary re-rendering.

ParcelBoundaries have an internal action buffer that can hold onto changes as they exit the boundary. These are normally released immediately, but also allow for debouncing changes, or putting a hold on all changes so they can be released later.

import {ParcelBoundary} from 'react-dataparcels';
<ParcelBoundary
    parcel={Parcel}
    debounce={?number}
    pure={?boolean}
    forceUpdate={?Array<*>}
    hold={?boolean}
    debugBuffer={?boolean}
    debugParcel={?boolean}
>
    {(parcel, actions, buffered) => Node}
</ParcelBoundary>
ParcelBoundary is also available as a React higher order component, ParcelBoundaryHoc.

Children

childRenderer

(parcel: Parcel, actions: ParcelBoundaryActions, buffered: boolean) => Node
ParcelBoundaryActions = {
    release: () => void,
    cancel: () => void
}

ParcelBoundaries must be given a childRenderer function as children. This is called whenever the ParcelBoundary updates.

It is passed a parcel, a set of actions, and a buffered boolean.

  • The parcel is on the “inside” of the parcel boundary, and is able to update independently of the parcel that was passed into the ParcelBoundary.
  • The actions can be used to control the ParcelBoundary’s action buffer (see the hold example).
  • The buffered boolean indicates if the ParcelBoundary currently contains changes that it hasn’t yet released.

The return value of childRenderer will be rendered.

// personParcel is a Parcel
<ParcelBoundary parcel={personParcel}>
    {(parcel, actions) => {
        return <input type="text" {...parcel.spreadDOM} />;
    }}
</ParcelBoundary>

Props

parcel

parcel: Parcel

The parcel that the ParcelBoundary will apply to. By default the ParcelBoundary will only update when parcel's data changes.

The parcel can be accessed from inside the ParcelBoundary via the first argument of the child renderer function, as shown here.

// personParcel is a Parcel
<ParcelBoundary parcel={personParcel}>
    {(personParcel) => {
        // personParcel is now inside the ParcelBoundary
        return <input type="text" {...personParcel.spreadDOM} />;
    }}
</ParcelBoundary>
Example

debounce

debounce?: number // optional

If set, debounce will debounce any changes that occur inside the ParcelBoundary. The number indicates the number of milliseconds to debounce.

This can be used to increase rendering performance for parcels that change value many times in rapid succession, such as text inputs.

Debouncing explained

When the parcel in the ParcelBoundary sends a change, the ParcelBoundary will catch it and prevent it from being propagated out of the boundary. The parcel on the inside of the ParcelBoundary will still update as normal.

The ParcelBoundary waits until no new changes have occured for debounce number of milliseconds. It then releases all the changes it has buffered, all together in a single change request.

Debouncing can be good for rendering performance because parcels outside the ParcelBoundary don’t needlessly update every time a small change occurs (e.g. each time the user presses a key).

// personParcel is a Parcel
<ParcelBoundary parcel={personParcel} debounce={100}>
    {(personParcel) => <input type="text" {...personParcel.spreadDOM} />}
</ParcelBoundary>
Example

pure

pure?: boolean = true // optional

Enables pure rendering. When pure is true, ParcelBoundary will only re-render when parcel's data changes. It defaults to true.

Use forceUpdate if you would like ParcelBoundary to re-render in response to changes in other props.

forceUpdate

forceUpdate?: Array<*> // optional

While a ParcelBoundary is using pure rendering, forceUpdate will force the ParcelBoundary to re-render in response to changes in other props. Each item in the forceUpdate array is compared using strict equality against its previous values, and if any are not strictly equal, the ParcelBoundary will re-render.

// personParcel is a Parcel
// options is an array of options that are loaded after mount

<ParcelBoundary parcel={personParcel} forceUpdate={[options]}>
    {(personParcel) => <Select {...personParcel.spreadDOM} options={options} />}
</ParcelBoundary>
Example

hold

hold?: boolean = false // optional

When hold is true, all changes made to the parcel inside the ParcelBoundary are prevented from being propagated out of the boundary. The inner parcel will continue to update as normal. You can then call actions.release() to release all the buffered changes at once, or actions.cancel() to cancel all the buffered changes. This can be useful for building UIs that have a submit action.

// personParcel is a Parcel
<ParcelBoundary parcel={personParcel}>
    {(personParcel, {release, cancel}) => {
        // personParcel is now inside the ParcelBoundary
        return <div>
            <input type="text" {...personParcel.spreadDOM} />
            <button onClick={() => release()}>Submit</button>
            <button onClick={() => cancel()}>Cancel</button>
        </div>;
    }}
</ParcelBoundary>
Example

debugBuffer

debugBuffer?: boolean = false // optional

Wehn debugBuffer is true, ParcelBoundary will log out changes relating to its internal action buffer.

debugParcel

debugParcel?: boolean = false // optional

Wehn debugParcel is true, ParcelBoundary will log out changes to its current parcel state.