Skip to content
This repository has been archived by the owner on Mar 5, 2023. It is now read-only.
This repository has been archived by the owner on Mar 5, 2023. It is now read-only.

createMachine calls can only appear in the variable declaration or as a default export #77

Open
@Newbie012

Description

Following the Reddit tutorial, there's a section that demonstrates splitting machines. In that section, they create a factory that creates a machine given a subreddit name. This is my translation to typescript

import { assign, createMachine } from "@xstate/compiled";

type SubredditContext = {
    subreddit: string;
    posts?: unknown[];
    lastUpdated?: Date;
    error?: string;
};

export type SubredditEvent = { type: "REFRESH" } | { type: "RETRY" };

export const createSubredditMachine = (subreddit: string) => {
  return createMachine<SubredditContext, SubredditEvent, "subreddit">({
    id: "subreddit",
    initial: "loading",
    context: {
      subreddit,
      posts: undefined,
      lastUpdated: undefined,
      error: undefined,
    },
    states: {
      loading: {
        invoke: {
          id: "fetch-subreddit",
          src: invokeFetchSubreddit,
          onDone: {
            target: "loaded",
            actions: assign({
              posts: (_, event) => event.data,
              lastUpdated: (_) => new Date(),
            }),
          },
          onError: "failure",
        },
      },
      loaded: {
        on: {
          REFRESH: "loading",
        },
      },
      failure: {
        on: {
          RETRY: "loading",
        },
      },
    },
  });
};

function invokeFetchSubreddit(context: SubredditContext) {
  const { subreddit } = context;

  return fetch(`https://www.reddit.com/r/${subreddit}.json`)
    .then((res) => res.json())
    .then((json) => json.data.children.map((child: any) => child.data));
}

As you may guess, xstate-codegen has an issue with it since we're not exporting the machine. The only thing that I can come up with is:

  1. extract the createMachine outside of the function and export it.
  2. set context.subreddit as optional.
  3. Change createSubredditMachine to:
export const createSubredditMachine = (subreddit: string) => {
    subredditMachine.withContext({ subreddit });
};

The only thing that bugs me is that I had to set the subreddit as optional. Is there a better way of handling this?

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions