xstate icon indicating copy to clipboard operation
xstate copied to clipboard

v5 - Bug: Context from machine.withContext() is ignored for React's useMachine

Open Valkendorm opened this issue 3 years ago • 2 comments

Description

When using useMachine from a machine where withContext has been used, the resulting machine's state will have the original machine's context.

Example from reproduction's link:

// Where machine's context is { count: 0 }
const [state] = useMachine(toggleMachine.withContext({ count: 5 }));

Just started experimenting with V5. Please tell me if I should report other issues I may find (or contribute to fix).

Expected result

{ count: 5 }

Actual result

{ count: 0 }

Reproduction

https://codesandbox.io/s/dreamy-rubin-17lmfv?file=/src/index.js

Additional context

Versions

xstate: 5.0.0-alpha.0 @xstate/react: 4.0.0-alpha.0

Valkendorm avatar May 27 '22 20:05 Valkendorm

Thanks for testing out our newest alpha releases! It's really appreciated.

I already see what's wrong - gonna prepare a PR soon for this problem.

Andarist avatar May 27 '22 21:05 Andarist

Actually... I could fix this particular issue somewhat quickly but this has shown me that how context values are "merged" is actually kinda complicated right now. So I think I will take this as an opportunity to rethink this and maybe simplify it if possible. This input RFC has also the potential for substantially changing the code here so I think it makes sense to think about fixing this problem when we decide what to do about input

Andarist avatar May 27 '22 21:05 Andarist

The .withContext({ ... }) method is removed. Using input (xstate@beta) is now the recommended way of doing this:

import "./styles.css";
import React from "react";
import ReactDOM from "react-dom";
import { createMachine } from "xstate";
import { useMachine } from "@xstate/react";

const toggleMachine = createMachine({
  id: "toggle",
  context: ({ input }) => ({
    count: input?.count ?? 0
  })
});

function App() {
  const [withInputState] = useMachine(toggleMachine, {
    input: { count: 5 }
  });

  return (
    <div className="App">
      <h1>Initial State's context</h1>
      <pre>{JSON.stringify(toggleMachine.initialState.context)}</pre>
      <h1>Context when using input</h1>
      <pre>{JSON.stringify(withInputState.context)}</pre>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

https://codesandbox.io/s/damp-sun-wxh CleanShot 2023-04-16 at 13 05 14@2x fys?file=/src/index.js:0-749

davidkpiano avatar Apr 16 '23 17:04 davidkpiano