ParcelHoc

ParcelHoc is a React higher order component. Its job is to provide a parcel as a prop, and to handle how the parcel binds to React props and lifecycle events.

It is recommended that you use ParcelHoc, rather than managing your own Parcel state.

import ParcelHoc from 'react-dataparcels/ParcelHoc';
ParcelHoc({
    name: string,
    valueFromProps: Function,
    shouldParcelUpdateFromProps?: Function,
    onChange?: Function,
    modifyBeforeUpdate: Array<Function>,
    delayUntil?: Function,
    pipe?: Function
    // debugging options
    debugParcel?: boolean
});

Config

name

name: string

Sets the name of the prop that will contain the parcel.

Example

valueFromProps

valueFromProps: (props: Object) => any

The valueFromProps function will be called once when ParcelHoc mounts. It is passed props, and the returned value is used as the initial value of the ParcelHoc’s Parcel.

Example

shouldParcelUpdateFromProps

shouldParcelUpdateFromProps?: (prevProps: *, nextProps: *) => boolean // optional

The shouldParcelUpdateFromProps config option allows the ParcelHoc to replace its parcel’s contents based on received props.

If shouldParcelUpdateFromProps is set, it will be called every time props are received. It is passed three arguments:

  • prevProps is the previous set of props received.
  • nextProps is the next set of props received.
  • valueFromProps is the function passed to config.valueFromProps

When shouldParcelUpdateFromProps returns true, ParcelHoc will replace all of its parcels value with valueFromProps(nextProps), and it will delete all key and meta information from the parcel.

ParcelHoc({
    name: "exampleParcel",
    valueFromProps: (props) => props.data,
    shouldParcelUpdateFromProps: (prevProps, nextProps, valueFromProps) => valueFromProps(prevProps) !== valueFromProps(nextProps)
});
In future there will be more options to allow key and meta data to be retained.
Example

onChange

onChange?: (props: Object) => (value: any, changeRequest: ChangeRequest) => void // optional

The onChange function is called whenever ParcelHoc changes. It expects to be given a double barrel function. The first function will be passed props, and the next is passed the new value. It is only fired if the value actually changes.

onChange is often used to relay changes further up the React DOM heirarchy. This works in a very similar way to uncontrolled components in React.

Example

modifyBeforeUpdate

modifyBeforeUpdate?: Array<Updater>

// updating value - only to be used if shape doesn't change
type Updater = (value: any, changeRequest: ChangeRequest) => any;

// updating shape, including meta
type Updater = shape((parcelShape: ParcelShape, changeRequest: ChangeRequest) => any);

The modifyBeforeUpdate config option allows derived data to be set on a Parcel. Whenever the data in a ParcelHoc is about to be initialised or updated in any way, it is passed through all modifyBeforeUpdate functions.

Each function in the modifyBeforeUpdate array operates just like the updater provided to Parcel.modifyUp().

ParcelHoc({
    name: "exampleParcel",
    valueFromProps: (props) => ({
        number: 99,
        isOdd: undefined
        // ^ this will contain derived data
    }),
    modifyBeforeUpdate: [
        (value) => ({
            ...value,
            isOdd: (value.number % 2 === 1)
        })
    ]
});

// exampleParcel.value.isOdd equals true
exampleParcel.set('number', 100);
// exampleParcel.value.isOdd now equals false

Please be careful

This method is safe to use without shape() in most cases, but in some cases it should not be used:

  • If the updater gives you a primitive value or childless value, you can return anything.
  • If the updater gives you a value that has children, you can always return a primitive value or childless value.
  • If the updater gives you a value that has children, you can return a value with children only if the shape hasn’t changed.

Please ensure you do not change the shape of the value, as changing the data shape or moving children within the data shape can cause dataparcels to misplace its keying and meta information! Dataparcels stores data against each part of a deep value’s data structure, so it can only let you change the value if you promise not to alter the shape.

// example updaters
string => string + "!" // good
string => [string] // good
date => date.toString() // good
array => array.join(".") // good
array => array.map(number => number + 1) // good, shape is still the same

array => array.slice(0,2) // bad, shape has changed if array is longer that 2!
array => array.reverse() // bad, shape has changed because items have moved around!

If you need to update the shape of the data, you can do so using dataparcels/shape. The shape function will wrap your Parcel’s data in a ParcelShape which allows for safe shape editing. See ParcelShape for more details.

import shape from 'dataparcels/shape';

let parcel = new Parcel({
    value: [1,2,3]
});

let modifiedParcel = parcel.modifyDown(shape(parcelShape => parcelShape
    .push("foo")
    .push("bar")
    .setMeta({
        cool: true
    })
));

delayUntil

delayUntil?: (props: Object) => boolean // optional

You can delay the creation of the parcel by providing an delayUntil function. It will be called on mount and at every prop change until the parcel is created. It is passed props, and the Parcel will not be created until true is returned. A value of undefined will be passed down until the Parcel is created. Once the returned value is true, the Parcel will be created with the props at that time.

Example

pipe

pipe?: (props: Object) => (parcel: Parcel) => Parcel // optional

This function gives you the opportunity to modify the parcel before it reaches any other components.

The pipe function expects to be given a double barrel function. The first function will be passed props, and the next is passed the Parcel. The result of the pipe function will then be passed down as a prop.

debugParcel

debugParcel?: boolean = false // optional

For debugging purposes. When set to true this logs the ParcelHoc’s parcel each time it changes.

Child props

${name}

${name}: Parcel

ParceHoc’s child component will receive a Parcel as a prop, with the name of the prop specified by config.name.