useParcelState

The useParcelState function is a React hook. Its job is to provide you with a Parcel stored in React state, and to handle how the parcel responds to changes in React props.

By default, useParcelState operates in a similar way to an uncontrolled component, accepting an initial value once on first mount, and then becoming the master of its own state from then on. This behaviour can be changed using the updateValue parameter.

import useParcelState from 'react-dataparcels/useParcelState';
let [parcel] = useParcelState({
    value: any,
    // optional
    updateValue?: boolean,
    onChange?: Function,
    debounce?: number,
    beforeChange?: Function|Function[]
});
If you want a submittable form, consider using useParcelForm.

Params

value

value: any

Sets the initial value to be put into useParcelState’s Parcel.

let [parcel] = useParcelState({
    value: 100
});

// parcel.value is 100

parcel.set(200);

// set() triggers a change and a re-render
// parcel.value is now 200

If computing value is a heavy operation, you can return the value from a function. The function will only be called on initial mount. However, if updateValue is set to true then the function will be called on every update.

let [parcel] = useParcelState({
    value: () => 100
});

// parcel.value is 100

updateValue

updateValue?: boolean = false // optional

When updateValue is set to true during an update, the useParcelState hook will check to see if value has changed, and will update its Parcel’s value if so. This will completely replace any changes that may have happened to the Parcel since the last time value was put into the Parcel.

Value changes are detected using Object.is(), comparing the new value with the previous one.

// receivedValue is 100

let [parcel] = useParcelState({
    value: receivedValue,
    updateValue: true
});

// parcel.value is 100

parcel.set(200);

// set() triggers a change and a re-render
// parcel.value is now 200

// if component updates and receivedValue is now 300
// then parcel.value is now 300

onChange

onChange?: (parcel: Parcel, changeRequest: ChangeRequest) => void // optional

If provided, this function is called whenever useParcelState’s Parcel has handled a change. It receives the new Parcel, and the ChangeRequest that was responsible for the change.

This function can be used to relay changes further up the React heirarchy.

Please keep in mind that it is possible for a change to result in the same data being contained in the Parcel, onChange will not dedupe subsequent calls whose Parcels contain the same data.

let [parcel] = useParcelState({
    value: receivedValue,
    onChange: (parcel, changeRequest) => {
        // add logic here
    }
});

debounce

debounce?: number // optional

If set, debounce will debounce the calls to onChange. The number indicates the number of milliseconds to debounce.

This can be used to limit how rapidly onChange may be called in quick succession.

Debouncing explained

The useParcelState hooks waits until no new changes have occured for debounce number of milliseconds. It then calls onChange with the most recent Parcel and ChangeRequest.

let [parcel] = useParcelState({
    value: receivedValue,
    onChange: (parcel, changeRequest) => {
        // add logic here
    },
    debounce: 500
});

beforeChange

beforeChange?: ParcelValueUpdater|ParcelValueUpdater[] // optional

type ParcelValueUpdater = (value: any, changeRequest: ChangeRequest) => any
type ParcelValueUpdater = shape((parcelShape: ParcelShape, changeRequest: ChangeRequest) => any);

The beforeChange parameter accepts either a single function, or an array of functions. Whenever a new value is taken into useParcelState from params, and whenever the useParcelState hook recieves a change from below, the change is passed through each beforeChange function.

Internally the useParcelBuffer hook uses Parcel.modifyUp() on each of the beforeChange functions. If more than one function is passed to beforeChange, the change will go through the first function in the array first, then the second etc.

This is particularly useful for setting derived data, and plugins such as validation are built to be passed into beforeChange.

Please be careful

This method is safe to use in most simple 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.

To find out why, and what to do about it, please read about value updaters.

let [parcel] = useParcelState({
    value: "ABC",
    beforeChange: value => value.toLowerCase()
});

// ^ "ABC" will be passed through `beforeChange`
// and useParcelState's Parcel will contain a value of "abc"
// parcel.value is now "abc"

parcel.set("HELLO");

// ^ "HELLO" will be passed through `beforeChange`
// and useParcelState's Parcel will contain a value of "hello"
// parcel.value is now "hello"

Returns

[parcel: Parcel]

parcel

parcel: Parcel

The useParcelState hook returns an array containing a single element, the Parcel that it holds in React state.