Why is useActionData returning undefined in my Shopify remix run code?

Topic summary

A developer learning Shopify and Remix is encountering an issue where useActionData() returns undefined when called in their component.

Code Context:

  • They’ve defined an action function that returns JSON data with a data field and a number property
  • Using useActionData() hook to access the returned data
  • Attempting to log actionData?.data to the console

The Problem:
The actionData variable is coming back as undefined, preventing access to the expected return values from the action function.

Additional Question:
The developer also asks how to make GraphQL calls from custom functions (not actions).

Note: The code snippet appears corrupted or reversed in parts, making it difficult to identify potential syntax errors or implementation issues that might be causing the undefined return value. The discussion remains open with no responses or solutions provided yet.

Summarized with AI on November 16. AI used: claude-sonnet-4-5-20250929.

Hey, I’m studing shopify and remis and I don’t understand how is useActionData working.
There’s the code:

import {useState} from "react";
import { json } from "@remix-run/node";
import {
  Page,
  Layout,
  EmptyState,
} from "@shopify/polaris";
import ProductList from "../../components/ProductList";
import {useActionData, useSubmit} from "@remix-run/react";

export async function action({ request }) {
  return json({
    data: request.data,
    number: 12,
  });
}

export default function Index() {
  const [selectedIds, setSelectedIds] = useState([]);
  const submit = useSubmit();
  const actionData = useActionData();
  console.log(actionData?.data)

  const doIt = async () => {
    const selected = await shopify.resourcePicker({type: 'product', action: 'select', multiple: true});
    if (selected?.length) {
      setSelectedIds(selected);
      submit({data: selected})
    }
  }

  let isEmptyState = !selectedIds.length;

  return (
    <Page>
      <Layout>
        <Layout.Section>
            {
              isEmptyState ? <EmptyState
                heading="Manage your inventory transfers"
                action={{content: 'Add transfer1123', onAction: doIt}}
                image="https://cdn.shopify.com/s/files/1/0262/4071/2726/files/emptystate-files.png"
              />
                :  <ProductList />
            }
            <div>{actionData?.toString() || 'no'}</div>
        </Layout.Section>
      </Layout>
    </Page>
  );
}

And I have a second question. How I can do gql calls from my custom functions (not action).
Thanks!