Skip to content

Commit

Permalink
[@xstate/store] Add examples + update createStoreWithProducer(…) (#…
Browse files Browse the repository at this point in the history
…5079)

* Add simple example

* Update README.md

* Add object API for createStoreWithProducer + tests

* Fix ActorRefLike

* Update readme.md

* Add EnqueueObject type, make it work for createStoreWithProducer

* Update packages/xstate-store/src/store.ts

Co-authored-by: Mateusz Burzyński <[email protected]>

* Improve typecheck

* Update XState Store readme

* Add changeset

* Move example

* Revert package.json change

* Add failing inspect test

* Fix inspection types

* Update example packages

* Update pnpm-lock.yaml

* Add changeset

* Add deprecation

---------

Co-authored-by: Mateusz Burzyński <[email protected]>
  • Loading branch information
davidkpiano and Andarist authored Sep 20, 2024
1 parent ee3efba commit 2596396
Show file tree
Hide file tree
Showing 19 changed files with 2,655 additions and 2,177 deletions.
5 changes: 5 additions & 0 deletions .changeset/bright-geckos-brake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'xstate': patch
---

The inspection event interfaces now expect `ActorRefLike` instead of `AnyActorRef`
32 changes: 32 additions & 0 deletions .changeset/moody-rabbits-whisper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
'@xstate/store': minor
---

The `createStoreWithProducer(…)` function now uses the new configuration API:

```ts
import { createStoreWithProducer } from '@xstate/store';
// DEPRECATED API
// const store = createStoreWithProducer(
// producer,
// {
// count: 0
// },
// {
// inc: (context, event) => {
// context.count++;
// }
// }
// );

const store = createStoreWithProducer(producer, {
context: {
count: 0
},
on: {
inc: (context, event) => {
context.count++;
}
}
});
```
3 changes: 2 additions & 1 deletion examples/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ These steps assume You've forked the repo and created a branch for your PR. For

```bash
pnpm create vite@latest my-example-react --template react-ts
cd my-example-react
```

2. Install `xstate` and the library-specific beta (e.g. `@xstate/react`):

```bash
pnpm i xstate @xstate/react
pnpm install xstate @xstate/react
```

3. Add your XState-powered demo code ✨
Expand Down
28 changes: 28 additions & 0 deletions examples/store-counter-react/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import js from '@eslint/js';
import globals from 'globals';
import reactHooks from 'eslint-plugin-react-hooks';
import reactRefresh from 'eslint-plugin-react-refresh';
import tseslint from 'typescript-eslint';

export default tseslint.config(
{ ignores: ['dist'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.{ts,tsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser
},
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh
},
rules: {
...reactHooks.configs.recommended.rules,
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true }
]
}
}
);
24 changes: 13 additions & 11 deletions examples/store-counter-react/package.json
Original file line number Diff line number Diff line change
@@ -1,29 +1,31 @@
{
"name": "@xstate/example-store-counter-react",
"name": "counter-react",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"@xstate/store": "^0.0.2",
"@statelyai/inspect": "^0.4.0",
"@xstate/store": "^2.5.0",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@types/react": "^18.3.5",
"@eslint/js": "^9.10.0",
"@types/react": "^18.3.8",
"@types/react-dom": "^18.3.0",
"@typescript-eslint/eslint-plugin": "^7.18.0",
"@typescript-eslint/parser": "^7.18.0",
"@vitejs/plugin-react": "^4.3.1",
"eslint": "^8.57.0",
"eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-react-refresh": "^0.4.11",
"eslint": "^9.10.0",
"eslint-plugin-react-hooks": "5.1.0-rc-fb9a90fa48-20240614",
"eslint-plugin-react-refresh": "^0.4.12",
"globals": "^15.9.0",
"typescript": "^5.6.2",
"vite": "^5.4.5"
"typescript-eslint": "^8.6.0",
"vite": "^5.4.6"
}
}
47 changes: 38 additions & 9 deletions examples/store-counter-react/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,57 @@
import './App.css';
import { createStore } from '@xstate/store';
import { useSelector } from '@xstate/store/react';
import { useEffect } from 'react';
import { createBrowserInspector } from '@statelyai/inspect';

const store = createStore(
{
const inspector = createBrowserInspector();

const store = createStore({
context: {
count: 0
},
{
inc: {
count: (ctx) => ctx.count + 1
on: {
inc: (context, event: { by: number }) => {
return {
count: context.count + event.by
};
},
reset: (_context, _ev, { emit }) => {
emit({ type: 'reset' });
return {
count: 0
};
}
}
);
});

store.inspect(inspector.inspect);

function App() {
const count = useSelector(store, (s) => s.context.count);

useEffect(() => {
const sub = store.on('reset', () => {
console.log('Count reset!');
});

return sub.unsubscribe;
}, []);

return (
<>
<h1>XState Store counter example</h1>
<div className="card">
<button onClick={() => store.send({ type: 'inc' })}>
<div
className="card"
style={{
display: 'flex',
flexDirection: 'row',
gap: '.5rem'
}}
>
<button onClick={() => store.send({ type: 'inc', by: 1 })}>
count is {count}
</button>
<button onClick={() => store.send({ type: 'reset' })}>reset</button>
</div>
</>
);
Expand Down
1 change: 1 addition & 0 deletions examples/store-counter-react/src/assets/react.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 5 additions & 5 deletions examples/store-counter-react/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App.tsx';
import './index.css';

ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</React.StrictMode>
</StrictMode>
);
24 changes: 24 additions & 0 deletions examples/store-counter-react/tsconfig.app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,

/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",

/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"]
}
28 changes: 5 additions & 23 deletions examples/store-counter-react/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,25 +1,7 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,

/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",

/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}
19 changes: 15 additions & 4 deletions examples/store-counter-react/tsconfig.node.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"target": "ES2022",
"lib": ["ES2023"],
"module": "ESNext",
"skipLibCheck": true,

/* Bundler mode */
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
"strict": true
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,

/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["vite.config.ts"]
}
3 changes: 1 addition & 2 deletions packages/core/src/inspection.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {
ActorRefLike,
AnyActorRef,
AnyEventObject,
AnyTransitionDefinition,
Snapshot
Expand Down Expand Up @@ -51,7 +50,7 @@ export interface InspectedEventEvent extends BaseInspectionEventProperties {
// The source might not exist, e.g. when:
// - root init events
// - events sent from external (non-actor) sources
sourceRef: AnyActorRef | undefined;
sourceRef: ActorRefLike | undefined;
event: AnyEventObject; // { type: string, ... }
}

Expand Down
Loading

0 comments on commit 2596396

Please sign in to comment.