Data synchronisation

Data synchronisation encompasses how dataparcels interacts with pieces of data stored externally.

This part of the library is being developed and will be complete soon.

Saving data from a form

The simplest type of data synchronisation is a typical web form that can be submitted. Typical forms are often initially blank, or may occasionally preload some data from a server. Once the form is presented to the user it is the master of its own state. The data flow from this point on is unidirectional e.g. the form sends data to the server, and the server never pushes data back into the form.

This example makes use of the useParcelForm hook. This is the most commonly used hook, and is perfect for building submittable forms.

Request state: idle

personParcelState
{
    "firstname": "",
    "lastname": ""
}
personParcel
{
    "firstname": "",
    "lastname": ""
}
import React from 'react';
import useParcelForm from 'react-dataparcels/useParcelForm';
import ParcelBoundary from 'react-dataparcels/ParcelBoundary';

const initialValue = {
    firstname: "",
    lastname: ""
};

export default function SignUpForm(props) {

    let [personParcel, personParcelControl] = useParcelForm({
        value: initialValue,
        onSubmit: (parcel) => saveMyData(parcel.value)
        // ^ returns a promise
    });

    return <div>
        <label>firstname</label>
        <ParcelBoundary parcel={personParcel.get('firstname')}>
            {(firstname) => <input type="text" {...firstname.spreadDOM()} />}
        </ParcelBoundary>

        <label>lastname</label>
        <ParcelBoundary parcel={personParcel.get('lastname')}>
            {(lastname) => <input type="text" {...lastname.spreadDOM()} />}
        </ParcelBoundary>

        <button onClick={() => personParcelControl.submit()}>Submit</button>
    </div>;
}

Clearing a form after submit

You can set the data in the form to something else after it’s sent its data by setting onSubmitUseResult to true. The form’s current state will be replaced by whatever returned from onSubmit.

Request state: idle

personParcelState
{
    "firstname": "",
    "lastname": ""
}
personParcel
{
    "firstname": "",
    "lastname": ""
}
import React from 'react';
import useParcelForm from 'react-dataparcels/useParcelForm';
import ParcelBoundary from 'react-dataparcels/ParcelBoundary';

const initialValue = {
    firstname: "",
    lastname: ""
};

export default function SignUpForm(props) {

    let [personParcel, personParcelControl] = useParcelForm({
        value: initialValue,
        onSubmit: async (parcel) => {
            await saveMyData(parcel.value);
            return initialValue;
        },
        onSubmitUseResult: true
    });

    return <div>
        <label>firstname</label>
        <ParcelBoundary parcel={personParcel.get('firstname')}>
            {(firstname) => <input type="text" {...firstname.spreadDOM()} />}
        </ParcelBoundary>

        <label>lastname</label>
        <ParcelBoundary parcel={personParcel.get('lastname')}>
            {(lastname) => <input type="text" {...lastname.spreadDOM()} />}
        </ParcelBoundary>

        <button onClick={() => personParcelControl.submit()}>Submit</button>
    </div>;
}

Receiving data from the server after saving

Sometimes the data you’re editing in a form corresponds to data in a database somewhere. When this is the case, it’s important that the data in your form is an accurate representation of the data in the database whenever possible. Updating the state of your form after saving is a good way to ensure that the state held in your form is refreshed from the server periodically.

Both these examples show forms that make fake requests to a fake server. The fake server will remove any uppercase letters when it saves, and update the timeUpdated field. Try typing some uppercase letters into the form, and watch as the data is synchronised with the server’s data after the save completes.

Updating form data via props

If you’re using something like Redux, you’ll likely be receiving your data via props. That data from Redux should already update as a result of save operations. Use the updateValue parameter on useParcelForm to allow the form hook to update based on changes to your source data. Also make sure that the function that does the saving returns a promise, so useParcelForm can know if the request succeeded or not.

Time updated:

Request state: idle

personParcelState
{
    "firstname": "",
    "lastname": ""
}
personParcel
{
    "firstname": "",
    "lastname": ""
}
import React from 'react';
import useParcelForm from 'react-dataparcels/useParcelForm';
import ParcelBoundary from 'react-dataparcels/ParcelBoundary';

export default function PersonEditor(props) {

    let [personParcel, personParcelControl] = useParcelForm({
        value: props.personData,
        updateValue: true,
        onSubmit: (parcel) => props.dispatchMySaveAction(parcel.value)
    });

    // ^ dispatchMySaveAction should return a promise if it is
    // to work correctly with useParcelForm
    // The return value doesn't matter,
    // useParcelForm just wants to know
    // if the request succeeded or not

    let {timeUpdated} = personParcel.value;

    return <div>
        <label>firstname</label>
        <ParcelBoundary parcel={personParcel.get('firstname')}>
            {(firstname) => <input type="text" {...firstname.spreadDOM()} />}
        </ParcelBoundary>

        <label>lastname</label>
        <ParcelBoundary parcel={personParcel.get('lastname')}>
            {(lastname) => <input type="text" {...lastname.spreadDOM()} />}
        </ParcelBoundary>

        <p>Time updated: {timeUpdated.toLocaleString()}</p>

        <button onClick={() => personParcelControl.submit()}>Submit</button>
    </div>;
}

Updating form data via a promise

You may not have centralised state management like Redux in your app. In this case you can get useParcelForm to update based off the return value of the promise returned by the save function. To use this approach, set the onSubmitUseResult parameter to true.

Time updated:

Request state: idle

personParcelState
{
    "firstname": "",
    "lastname": ""
}
personParcel
{
    "firstname": "",
    "lastname": ""
}
import React from 'react';
import useParcelForm from 'react-dataparcels/useParcelForm';
import ParcelBoundary from 'react-dataparcels/ParcelBoundary';

export default function PersonEditor(props) {

    let [personParcel, personParcelControl] = useParcelForm({
        value: props.valueLoadedFromServer,
        onSubmit: (parcel) => saveMyData(parcel.value),
        onSubmitUseResult: true
    });

    let {timeUpdated} = personParcel.value;

    return <div>
        <label>firstname</label>
        <ParcelBoundary parcel={personParcel.get('firstname')}>
            {(firstname) => <input type="text" {...firstname.spreadDOM()} />}
        </ParcelBoundary>

        <label>lastname</label>
        <ParcelBoundary parcel={personParcel.get('lastname')}>
            {(lastname) => <input type="text" {...lastname.spreadDOM()} />}
        </ParcelBoundary>

        <p>Time updated: {timeUpdated.toLocaleString()}</p>

        <button onClick={() => personParcelControl.submit()}>Submit</button>
    </div>;
}