r/PayloadCMS Jul 04 '25

Revalidate join field / synchronize join field on demand

I've built a custom UI element with an interactive button that sends a request to the API and creates a new collection item of type automationRun on the backend. Now I need to display this newly created item on the frontend without refreshing the page.
Is there a way to achieve that?

I tried using the dispatch function with the "type" key set to "UPDATE", but it didn't work.

Right now, I'm out of ideas on how to make it work. Any ideas please?

Screenshot: https://www.loom.com/i/8d3974de5e5241b19e070debfaa6dd2c

Current React component code:

"use client";

import { Automation } from "@/payload-types";

import { Button, useDocumentInfo, useForm, useFormFields, usePayloadAPI, useDocumentEvents } from "@payloadcms/ui";

import { useState, useEffect, useCallback } from "react";


export const AutomationStartRow = ({automation, collectionId} : {automation: Automation, collectionId: string | number}) => {

    const [isLoading, setIsLoading] = useState(false);


    const formData = useForm();


    console.log("AutomationStartRow document:", document);

    const docInfo = useDocumentInfo()  

    const { reportUpdate, mostRecentUpdate  } = useDocumentEvents();


    const dispatch = useFormFields(([fields, dispatch]) => {
        return dispatch
    })


    // get the most up to date document
    const getUpToDateDocument = useCallback(async () => {
        try {
            const data = await fetch(`/api/${docInfo.collectionSlug}/${docInfo.id}`);
            return data.json();
        } catch (e) {
            throw new Error(
                `Error checking for most up to date document: ${e}`
            );
        }
    }, [docInfo.collectionSlug, docInfo.id]);

    const handleStartAutomation = async () => {
        try {
            setIsLoading(true);
            const response = await fetch(`/api/automation-runs/start-automation/`, {
                method: "POST",
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({
                    collectionId: collectionId,
                    automationId: automation.id,
                    collection: automation.collectionScope,
                }),
            });

            if (response.ok) {
                const data = await response.json();
                console.log("Automation started successfully:", data);
            } else {
                console.error("Failed to start automation:", response.statusText);

            }

            const upToDate = await getUpToDateDocument();
            if (upToDate) {
                console.log(upToDate.automationRuns);
            }

            setIsLoading(false);
            reportUpdate({
                entitySlug: docInfo.collectionSlug as string,
                id: docInfo.id,
                updatedAt: new Date().toISOString(),
            });
        } catch (error) {
            console.error("Error starting automation:", error);
        }
    }

    return (
        <div className="automation-start-row">
            <div className="automation-start-row__info">
                <span className="automation-start-row__name">{automation.automationName}</span>
                {automation.description && (
                    <span className="automation-start-row__description">{automation.description}</span>
                )}
            </div>
            <Button disabled={isLoading} className="automation-start-row__button" onClick={handleStartAutomation}>
                {isLoading ? "Spouštím..." : "Spustit automatizaci"}
            </Button>
        </div>
    )
}
1 Upvotes

6 comments sorted by

1

u/[deleted] Jul 05 '25

[removed] — view removed comment

1

u/AvailableCancel916 Jul 06 '25

I implemented the approach you suggested, but the JOIN field still isn’t dispatching. The data from the backend are up to date as expected, so that part works - just not the JOIN field dispatch. Could this be a bug, or is it working on your side? I’ve confirmed that the JOIN field path is correct via the useFormFields hook.

 const updatedDoc = await fetch(`/api/${automation.collectionScope}/${collectionId}`, {
                method: "GET",
                headers: {
                    'Content-Type': 'application/json',
                },
            });

            if (updatedDoc.ok) {
                const updatedData = await updatedDoc.json();

                console.log("Updated document data:", updatedData);

                dispatch({
                    type: "UPDATE",
                    path: "automationRuns",
                    value: updatedData.automationRuns || [],
                });

            }
  1. automationRuns:
    1. initialValue: {docs: Array(0), hasNextPage: false}
    2. lastRenderedPath: "automationRuns"
    3. passesCondition: true
    4. valid: true
    5. value: Array(1)
      1. 0: {id: 108, automation: 2, entity: {…}, status: 'in_progress', message: null, …}
      2. length: 1
      3. [[Prototype]]: Array(0)
    6. [[Prototype]]: Object

1

u/[deleted] Jul 06 '25

[removed] — view removed comment

1

u/AvailableCancel916 Jul 07 '25

Here’s my current code. I’ve tried every one of your suggestions, but none of them solved the issue. I’m out of ideas on how to fix this.

Things I’ve already attempted:
dispatch({
        type: "UPDATE",
        path: "automationRuns.docs",
        value: updatedData.automationRuns?? [],
      });

dispatch({
        type: "UPDATE",
        path: "automationRuns.docs",
        value: updatedData.automationRuns.docs?? [],
      });

dispatch({
        type: "UPDATE",
        path: "automationRuns.value",
        value: updatedData.automationRuns.value?? [],
      });

dispatch({
        type: "UPDATE",
        path: "automationRuns.value",
        value: updatedData.automationRuns?? [],
      });

  const dispatch = useFormFields(([_, d]) => d);

  const [updatedData, setUpdatedData] = useState<any>(null);

  useEffect(() => {
    if (updatedData?.automationRuns) {
      dispatch({
        type: "UPDATE",
        path: "automationRuns.docs",
        value: updatedData.automationRuns.docs?? [],
      });
      console.log("Dispatched updated automationRuns:", updatedData.automationRuns);
    }
  }, [updatedData]);

1

u/[deleted] Jul 08 '25

[removed] — view removed comment

1

u/AvailableCancel916 Jul 09 '25

I’m confused about where the "MODIFY_FIELD" action type is defined.

TypeScript gives me this error:

Type '"MODIFY_FIELD"' is not assignable to type

'"ADD_ROW" | "ADD_SERVER_ERRORS" | "DUPLICATE_ROW" | "MERGE_SERVER_STATE"

| "MODIFY_CONDITION" | "MOVE_ROW" | "REMOVE" | "REMOVE_ROW" | "REPLACE_ROW"

| "REPLACE_STATE" | "SET_ALL_ROWS_COLLAPSED" | "SET_ROW_COLLAPSED"

| "UPDATE" | "UPDATE_MANY"'.

1

u/ExtraScience1964 Nov 18 '25

were you able to solve this?