Skip to content
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 opened this issue Apr 18, 2021 · 1 comment

Comments

@Newbie012
Copy link

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?

@mattpocock
Copy link
Owner

@Newbie012 Agree! The fact that we don't support factory machines is not exactly great, since they're a fantastic way to use XState.

@Andarist's PR will support this, though. Pretty much all the issues on the board are due to the Babel-based extraction mechanism, which #29 will replace entirely.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants