beekai-oss / little-state-machine Goto Github PK
View Code? Open in Web Editor NEW📠 React custom hook for persist state management
Home Page: https://lrz5wloklm.csb.app/
License: MIT License
📠 React custom hook for persist state management
Home Page: https://lrz5wloklm.csb.app/
License: MIT License
little-state-machine type are not fully accurate as follows:
I think we need to improve DX as follows:
I want to create PR, but useStateMachine
argument updateStoreFunction
is difficult to support undefined
or {[key: string]: UpdateStoreFunction}
😢
My halfway results: kotarella1110@b061c77
Hello I'm receiving an error when trying to install. Any help would be appreciated. Thank you
0 verbose cli [
0 verbose cli 'C:\\Program Files\\nodejs\\node.exe',
0 verbose cli 'C:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js',
0 verbose cli 'i',
0 verbose cli 'little-state-machine'
0 verbose cli ]
1 info using [email protected]
2 info using [email protected]
3 timing npm:load:whichnode Completed in 0ms
4 timing config:load:defaults Completed in 1ms
5 timing config:load:file:C:\Program Files\nodejs\node_modules\npm\npmrc Completed in 2ms
6 timing config:load:builtin Completed in 2ms
7 timing config:load:cli Completed in 2ms
8 timing config:load:env Completed in 0ms
9 timing config:load:file:C:\Users\aaron\code\react\consumer-app\.npmrc Completed in 1ms
10 timing config:load:project Completed in 3ms
11 timing config:load:file:C:\Users\aaron\.npmrc Completed in 0ms
12 timing config:load:user Completed in 0ms
13 timing config:load:file:C:\Users\aaron\AppData\Roaming\npm\etc\npmrc Completed in 0ms
14 timing config:load:global Completed in 0ms
15 timing config:load:validate Completed in 0ms
16 timing config:load:credentials Completed in 1ms
17 timing config:load:setEnvs Completed in 1ms
18 timing config:load Completed in 10ms
19 timing npm:load:configload Completed in 11ms
20 timing npm:load:setTitle Completed in 1ms
21 timing config:load:flatten Completed in 2ms
22 timing npm:load:display Completed in 3ms
23 verbose logfile C:\Users\aaron\AppData\Local\npm-cache\_logs\2022-04-26T22_15_14_575Z-debug-0.log
24 timing npm:load:logFile Completed in 9ms
25 timing npm:load:timers Completed in 0ms
26 timing npm:load:configScope Completed in 0ms
27 timing npm:load Completed in 24ms
28 timing arborist:ctor Completed in 0ms
29 silly logfile start cleaning logs, removing 2 files
30 timing idealTree:init Completed in 677ms
31 timing idealTree:userRequests Completed in 4ms
32 silly idealTree buildDeps
33 silly fetch manifest little-state-machine@*
34 timing arborist:ctor Completed in 0ms
35 http fetch GET 200 https://registry.npmjs.org/little-state-machine 863ms (cache revalidated)
36 silly fetch manifest react@^18.0.0
37 http fetch GET 200 https://registry.npmjs.org/react 53ms (cache revalidated)
38 silly fetch manifest react@^16.8.0 || ^17
39 timing idealTree Completed in 1619ms
40 timing command:i Completed in 1631ms
41 verbose stack Error: unable to resolve dependency tree
41 verbose stack at Arborist.[failPeerConflict] (C:\Program Files\nodejs\node_modules\npm\node_modules\@npmcli\arborist\lib\arborist\build-ideal-tree.js:1362:25)
41 verbose stack at Arborist.[loadPeerSet] (C:\Program Files\nodejs\node_modules\npm\node_modules\@npmcli\arborist\lib\arborist\build-ideal-tree.js:1328:34)
41 verbose stack at async Arborist.[buildDepStep] (C:\Program Files\nodejs\node_modules\npm\node_modules\@npmcli\arborist\lib\arborist\build-ideal-tree.js:935:11)
41 verbose stack at async Arborist.buildIdealTree (C:\Program Files\nodejs\node_modules\npm\node_modules\@npmcli\arborist\lib\arborist\build-ideal-tree.js:216:7)
41 verbose stack at async Promise.all (index 1)
41 verbose stack at async Arborist.reify (C:\Program Files\nodejs\node_modules\npm\node_modules\@npmcli\arborist\lib\arborist\reify.js:149:5)
41 verbose stack at async Install.exec (C:\Program Files\nodejs\node_modules\npm\lib\commands\install.js:157:5)
41 verbose stack at async module.exports (C:\Program Files\nodejs\node_modules\npm\lib\cli.js:66:5)
42 verbose cwd C:\Users\aaron\code\react\consumer-app
43 verbose Windows_NT 10.0.22000
44 verbose argv "C:\\Program Files\\nodejs\\node.exe" "C:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js" "i" "little-state-machine"
45 verbose node v16.14.0
46 verbose npm v8.3.1
47 error code ERESOLVE
48 error ERESOLVE unable to resolve dependency tree
49 error
50 error While resolving: �[1mrm�[22m@�[1m0.1.0�[22m
50 error Found: �[1mreact�[22m@�[1m18.1.0�[22m�[2m�[22m
50 error �[2mnode_modules/react�[22m
50 error �[1mreact�[22m@"�[1m^18.0.0�[22m" from the root project
50 error
50 error Could not resolve dependency:
50 error �[35mpeer�[39m �[1mreact�[22m@"�[1m^16.8.0 || ^17�[22m" from �[1mlittle-state-machine�[22m@�[1m4.2.4�[22m�[2m�[22m
50 error �[2mnode_modules/little-state-machine�[22m
50 error �[1mlittle-state-machine�[22m@"�[1m*�[22m" from the root project
50 error
50 error Fix the upstream dependency conflict, or retry
50 error this command with --force, or --legacy-peer-deps
50 error to accept an incorrect (and potentially broken) dependency resolution.
50 error
50 error See C:\Users\aaron\AppData\Local\npm-cache\eresolve-report.txt for a full report.
51 verbose exit 1
52 timing npm Completed in 1903ms
53 verbose unfinished npm timer reify 1651011314836
54 verbose unfinished npm timer reify:loadTrees 1651011314846
55 verbose unfinished npm timer idealTree:buildDeps 1651011315528
56 verbose unfinished npm timer idealTree:#root 1651011315529
57 verbose code 1
58 error A complete log of this run can be found in:
58 error C:\Users\aaron\AppData\Local\npm-cache\_logs\2022-04-26T22_15_14_575Z-debug-0.log
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: [email protected]
npm ERR! Found: [email protected]
npm ERR! node_modules/react
npm ERR! react@"^18.0.0" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^16.8.0 || ^17" from [email protected]
npm ERR! node_modules/little-state-machine
npm ERR! little-state-machine@"*" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR!
npm ERR! See C:\Users\aaron\AppData\Local\npm-cache\eresolve-report.txt for a full report.
npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\aaron\AppData\Local\npm-cache\_logs\2022-04-26T22_19_09_423Z-debug-0.log
Is there an out of the box solution for testing the store out of the box?
A "common" practice for Redux is to attach the store to window and use it inside Cypress, example:
if (window.Cypress) {
window.store = store;
}
But in the case of little state machine createStore
function doesn't return an instance that I can "hook" onto.
I guess I can check the storage, but that is a lot of work/logic inside a test, I would like to avoid it.
Is there a way to hydrate things on the SSR? or should I just delay using components that require state?
Hi! We are trying to make LSM work with disabled cookies in the browser. This disables localStorage and sessionStorage in most browsers. This makes even trying to access window.sessionStorage return an access denied exception.
Our solution is to call setStorageType and save to app memory if sessionStorage is disabled.
// Run this only if sessionStorage is disabled or does not exist
const state = {}
setStorageType({
setItem: (key, value) => {
state[key] = value
},
getItem: item => state[item],
})
Now normally this should work, but there appears to be a line in the LSM source that depends on sessionStorage being enabled, making our app crash.
let storageType: Storage = isClient
? window.sessionStorage
: {
getItem: payload => payload,
setItem: (payload: string) => payload,
clear: () => {},
length: 0,
key: (payload: number) => payload.toString(),
removeItem: () => {},
};
In the code above, window.sessionStorage is called, but this crashes our app if it is not available. Of course, we could (try to) use require with a try-catch instead of imports, but we'd rather avoid that.
Would you guys be open to returning null/undefined/otherwise ignore the error if window.sessionStorage is not allowed?
Thanks!
So i am trying to setup up testing for my project and all works well except when i try to create a mock/test provider for our test suite.
(nothing too fancy just Next.js 11 + Jest + RTL)
The main issue is that i want to move away from mocking the return value of useStateMachine in favor of just letting the lib do its job and i test the result of the render.
This is also hindering my ability to test click events since they rely on LSM state changes. (ie hook form controlled by lsm).
So i have working providers for react query, i would assume that they would work the same. i did a test with just creating a React.Context provider and that works just fine.
So the main error i am getting is that createStore({...mockStore}) comes back with
// works just fine with the query provider etc.
// When i add the provider to wrap other existing providers (ie query client for react-query) it fails
import * as React from 'react';
import { StateMachineProvider, createStore } from 'little-state-machine';
import { initialState } from '../../store/states';
import { QueryClient, QueryClientProvider } from 'react-query';
import { render } from '@testing-library/react';
const createTestQueryClient = () =>
new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
});
const mockStore = () =>
createStore({
...initialState
});
// HOC for rendering our ui components with the query client along with testing configs
export function renderWithClient(ui) {
mockStore();
const testQueryClient = createTestQueryClient();
const { rerender, ...result } = render(
<StateMachineProvider>
<QueryClientProvider client={testQueryClient}>{ui}</QueryClientProvider>
</StateMachineProvider>
);
return {
...result,
rerender: (rerenderUi) =>
rerender(
<StateMachineProvider>
<QueryClientProvider client={testQueryClient}>{rerenderUi}</QueryClientProvider>{' '}
</StateMachineProvider>
),
};
}
// Query Client Context wrapper for our tests, use this separately when we want to
// use it to render hooks outiside components for testing
export function createWrapper() {
const testQueryClient = createTestQueryClient();
mockStore();
return ({ children }) => (
<StateMachineProvider>
<QueryClientProvider client={testQueryClient}>{children}</QueryClientProvider>;
</StateMachineProvider>
);
}
}
i get the below error, which basically tells me that little state machine is undefined, and checking console confirms same.
TypeError: (0 , _littleStateMachine.createStore) is not a function
27 |
28 | const mockStore = () =>
> 29 | createStore({
| ^
30 | user,
31 | points,
32 | transactions,
at mockStore (__mocks__/utils/index.js:29:3)
at renderWithClient (__mocks__/utils/index.js:44:3)
This is how i would normally create all my mockProviders (for which all except LSM are 100% working)
Any ideas/thoughts? Has anyone created test suites with LSM provider?
Recently i tried to make it work with old browsers but i couldn't make it.
Hey,
If I replace the action here https://codesandbox.io/s/wild-dawn-ud8bq?file=/src/yourDetailsAction.ts
with an async fn it doesn't work. Async is not supported, right? Any plans for future releases?
e.g.
export async function updateFirstLastName(state, payload) {
return Promise.resolve({
...state,
...payload
});
}
Middle-wares receive the state just updated by the action.
Middle-wares could also receive:
With state, action name and payload, a middleware could do something like this:
function middleware(state, actionName, payload) {
if (actionName === 'specialAction') return state;
sendLogSomewhere(payload);
return {
...state,
...performMagic(state)
}
}
I'm building a react-hook-form
wizard and am trying to use the syncStores function.
When submitting a form to go to the next page, the entire state disappears, even if I'm just returning the existing sessionStorage.
Am I doing it right?
https://codesandbox.io/s/github/svict4/RHF-LSM-with-RR
It's probably because I don't know how to use the library properly, does anyone have a more concrete example of POSTing or GETing data from an endpoint for the transform function?
function log(store: any) {
console.log('this function logs the store:', store);
}
function PostData(store: any) {
console.log('this function will trigger an API call to post data'); // is this the best place to put it?
}
window.sessionStorage.setItem(
'formData',
'{"yourDetails": {"firstname": "bull", "lastname": "le", "addresses": [{"street": "street"}]}}',
);
const mergeStore = (sessionData: any, data: any) => merge(data, sessionData);
// where externalStoreData is provided from an API
const externalStoreData = {
yourDetails: { firstname: 'sdfsdf', middlename: 'dfsdfsdf' },
};
createStore(
{
yourDetails,
},
{
name: 'formData',
middleWares: [log, PostData],
syncStores: {
externalStoreName: 'API',
transform: ({ externalStoreData, currentStoreData }) => {
// just returning the current store doesn't seem to work after submit?
return JSON.parse(window.sessionStorage.formData);
},
},
},
);
Also, after setting the data in an action, I'd like to get state of the new store, so that I can pass it to my react-router function and do some logic. But state
contains the previous state before updating, what's a better way of getting the new state?
const onSubit = data => {
action(data);
console.log(state); // I want to access the NEW state after the update
props.history.push('./result'); // so I can use it here
};
Make possible to create multiple stateMachines without creating GlobalState type, just infer it from updateAction first argument, or pass as generic to useStateMachine
When trying to use your awesome state machine in my React native app i get the error:
Can't find variable: document.
I assume this is the DEV tools causing this problem. Any clues you can give me or timeline for implementation would be awesome
Thanks
Is there a way to delete stored values to get removed upon refreshing?
here's the codesandbox for it.
https://codesandbox.io/s/react-hook-form-wizard-form-complete-w32u0?
Hey dumb question as I seemingly can't read the type properly
if I set up multiple actions like so:
const { state, actions } = useStateMachine(
{ saveAction, sorryAction },
{ saveAction: "saveToDB", sorryAction: "sorry" }
);
how do I send an update to only one of the actions? it's not this:
actions([{ key: "sorry" }], {
reason: "you dun goofed"
});
I guess this is more a question or feature request: I would like to "subscribe" only to a part of the state to prevent unnecessary rerenders. For example ComponentA
may only use fieldA
of my global state. But currently if fieldB
is changed also ComponentA
is rerendered. Is there already any possibility to prevent this or could this be a future feature?
See this csb and watch the console for rerendering of the components.
Is there any way to create multiple stores while ensuring state type safety?
As far as I see you need to define a global definition file that corresponds to globalstate but i want to have several small stores instead.
PS: Thanks for creating this
master
branch failed. 🚨I recommend you give this issue a high priority, so other packages depending on you could benefit from your bug fixes and new features.
You can find below the list of errors reported by semantic-release. Each one of them has to be resolved in order to automatically publish your package. I’m sure you can resolve this 💪.
Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it.
Once all the errors are resolved, semantic-release will release your package the next time you push a commit to the master
branch. You can also manually restart the failed CI job that runs semantic-release.
If you are not sure how to resolve this, here is some links that can help you:
If those don’t help, or if this issue is reporting something you think isn’t right, you can always ask the humans behind semantic-release.
The npm token configured in the NPM_TOKEN
environment variable must be a valid token allowing to publish to the registry https://registry.npmjs.org/
.
If you are using Two Factor Authentication for your account, set its level to "Authorization only" in your account settings. semantic-release cannot publish with the default "
Authorization and writes" level.
Please make sure to set the NPM_TOKEN
environment variable in your CI with the exact value of the npm token.
Good luck with your project ✨
Your semantic-release bot 📦🚀
I expected the middlewares to behave like a pipe like with other libraries. Documentation didn't specify that, but I think it's typically more intuitive than the current implementation. Currently:
const storeData = getStore();
if (Array.isArray(middleWaresArray) && middleWaresArray.length) {
middleWaresArray.forEach((callback) => {
callback(storeData);
});
}
updateStore(storeData);
const storeData = getStore();
let pipeData;
if (Array.isArray(middleWaresArray) && middleWaresArray.length) {
pipeData = middleWaresArray.reduce((currentValue, currentFunction) => {
return currentFunction(currentValue);
}, storeData);
}
updateStore(pipeData);
I expect that after action(data) the state would be updated. But it remains the previous state. How do I access the updated state?
const onSubmit = (data) => {
action(data)
console.log('data:', data) // partial store
console.log('state:', state) // previous state
}
This is invoked using RHF:
<form onSubmit={handleSubmit(onSubmit)}>
Hi! When a log middleware is adding, the data
property of state
object is undefined
.
function log(store) {
console.log(store)
}
createStore({ data: {} }, { middleWares: [log] });
Here is a fork from React Hook Form - Wizard Form sandbox:
https://codesandbox.io/s/react-hook-form-wizard-form-whzkb?file=/src/index.js
Maybe it's related to: #35
I've noticed, even when building without <DevTools />
, react-json-view
is still bundled in the application. Perhaps this is intentional, but seems unnecessary. When bundled it takes up about 149KB uncompressed.
This might be a misunderstanding on my part, but this at least seems unexpected. I can't seem to get a working example where I reset the state of the form to where it started without refreshing the page manually.
I tried both calling the window.STATE_MACHINE_RESET
and creating a reset function that sets the state back to what the app started with. Neither of these seem to trigger the app to reload. Additionally, the DevTool reset button doesn't seem to actually reset the data in the DevTool without refreshing the window, which seems a bit odd to have a button that doesn't show any feedback.
Here is my modified demo app with the reset function. I added a reset button that triggers the reset function, which just sets the state back to the original.
Steps I'm taking in my demo app:
Also:
Hey, Thanks for the great package. I am trying to use this with Next.js but I get the following error when SSR is happening. Would you consider adding support for isomorphic apps in the future.
ReferenceError: window is not defined
createStore
./node_modules/little-state-machine/dist/index.js:164:9
Following the example at https://github.com/bluebill1049/little-state-machine#%EF%B8%8F-type-safety-ts does not override the GlobalState
Steps to repro:
custom-types/global.d.ts
tsconfig.json
using typedRoots: ['./custom-typings']
GlobalState
declarationimport 'little-state-machine';
declare module 'little-state-machine' {
interface GlobalState {
yourDetail: {
name: string;
};
}
}
Property 'yourDetail' does not exist on type 'GlobalState'. TS2339
8 | ...state,
9 | yourDetail: {
> 10 | ...state.yourDetail,
| ^
11 | ...payload,
12 | },
13 | });
Please see issue at https://codesandbox.io/s/sad-lamarr-ko811?file=/src/App.tsx
Could you please describe how to achieve the "reset" / window.STATE_MACHINE_RESET functionality upon form completion in production?
I would like to allow a new user to fill out the registration form after another user has already completed it.
I have useEffects in my codebase that have little-state-machine actions as dependencies, everything worked fine until I update little-state-machine from version "3.1.2"
to 4.1.0
. Now Actions call every time useEffect and re-render my components.
Also tried with TS demo sample from your docs, only added this effect :
useEffect(() => { console.log("called every time"); actions.updateFirstLastName({ yourDetails: { firstname: "testFirst", lastname: "testLast" } }); }, [actions]);
in Form.tsx
file. And got same result.
Not sure what to do, can someone help?
https://codesandbox.io/s/react-hook-form-wizard-form-13yud?file=/src/Step1.js
Per the example code sandbox the action(data)
line is giving the error above, I am trying to build off of this example, but unsure how to fix this error?
CreateStore
's middleWares
option expects globalState
to be returned, or undefined will be returned to the updateStore
function and will error.
https://codesandbox.io/s/little-state-machine-demo-zc30h
Thus, the super simple example in the readme does not work.
Expected: if nothing is returned from any middleWares
callback, that it retains the previous globalState
.
In my app, I want to use Little State Machine to share state between two separate component trees. However, when I tried to do so, one tree failed to update after an action was dispatched in the other. Is this expected behavior?
I've been trying to setStorageType(AsyncStorage)
in react native but it does not work. I've checked the index and it seems setStorageType
isn't provided. Is there support for react native at the moment?
My idea is to push data to an array with the same form. So everytime i press send, it appends it to the array.
Here is my following state:
createStore({
data: {
id: '1',
role: '',
name: '',
mail: '',
addictions: [],
phisiology_logs: [],
achievements: [],
},
});
And this is my form (using react-hook-form)
const onSubmit = (data) => {
console.log('state es, ', state.data.counter);
actions.updateAction(data);
console.log('data', data);
};
return (
<div className="">
<form action="" onSubmit={handleSubmit(onSubmit)}>
<div className="flex items-start space-x-4 pb-">
<div className="flex-shrink-0"></div>
<div className="flex-1 min-w-0">
<div className="overflow-hidden border border-gray-300 rounded-lg shadow-sm focus-within:border-indigo-500 focus-within:ring-1 focus-within:ring-indigo-500">
<label htmlFor="comment" className="sr-only">
Agrega tu comentario
</label>
<textarea
rows={3}
name=""
className="block w-full py-3 border-0 resize-none focus:ring-0 sm:text-sm"
placeholder="Add your comment..."
defaultValue={''}
{...register(
`phisiology_logs[0].description`,
{
required: 'Required',
}
)}
/>
</div>
<select
{...register(
`phisiology_logs[0].feel`,
{
required: true,
}
)}
className="block px-2 py-2 border border-gray-200 rounded-lg shadow-sm focus-within:border-indigo-500 focus-within:ring-1 focus-within:ring-indigo-500"
>
<option value="5">😁 Feliz</option>
<option value="4">😀 Bien</option>
<option value="3">😐 Neutro</option>
<option value="2 ">😥 Triste </option>
<option value="1">😭Muy Mal</option>
</select>
<input
type="date"
className="hidden"
defaultValue={
new Date().toISOString().split('T')[0]
}
placeholder="date"
{...register(
`phisiology_logs[0].date`,
{
required: true,
}
)}
/>
<button
type="submit"
className="inline-flex items-center px-4 py-2 text-sm font-medium text-white bg-indigo-600 border border-transparent rounded-md shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
>
Send
</button>
</div>
</div>
</form>
</div>
);
You can see im just adding this information to the index 0 of the phisiology_logs array. How can i append or push data to the state (data.phisiology_logs[]) object? So everytime i press 'Send' it pushes data to the array.
It looks like the sessionStorage lookup needs to be wrapped in a try catch to allow for Chrome users with cookies disabled:
src.f69400ca.js:116 Uncaught DOMException: Failed to read the 'sessionStorage' property from 'Window': Access is denied for this document.
at new e (http://localhost:1234/src.f69400ca.js:11651:87)
at Object.parcelRequire.../node_modules/little-state-machine/dist/little-state-machine.es.js.react (http://localhost:1234/src.f69400ca.js:11649:9)
at newRequire (http://localhost:1234/src.f69400ca.js:47:24)
at localRequire (http://localhost:1234/src.f69400ca.js:53:14)
at Object.parcelRequire.index.tsx.core-js/modules/es6.array.copy-within (http://localhost:1234/src.f69400ca.js:108133:30)
at newRequire (http://localhost:1234/src.f69400ca.js:47:24)
at http://localhost:1234/src.f69400ca.js:81:7
at http://localhost:1234/src.f69400ca.js:120:3
```
import AsyncStorage from '@react-native-community/async-storage'
import {StateMachineProvider, createStore, setStorageType} from 'little-state-machine'
setStorageType(AsyncStorage)
createStore(InitStore, {name: 'xxx'})
const App = () => {
return (
...
)
}
is this correct?
when i shake & reload the app, the store's gone
I have a list of questions with answer option yes and no. If I click on Yes , then it's value should add on store and when I click on No option, then it's value should remove from store. I want to manage by array.
What about adding a configuration option to choose between localStorage
& sessionStorage
?
I've tried to investigate using the transpiled code, but even the code sandbox is broken for react-hook-form
. Hoping to see what the issue was, but have to move forward on a project.
https://codesandbox.io/s/form-wizard-pages-kkg7m
I also saw that this useContext
is where it's using the state:
I read the docs but I didn't understand if I can manage a global state dispatching actions like Redux.
With this lib can I control Global State, access it and dispatch actions on any component or is just for local state management?
Now I see that source code in tag v3.0.2 (https://github.com/bluebill1049/little-state-machine/releases/tag/v3.0.2), doesn't contain changes for middleware.
In archive:
export const middleWare = (data: string = '') => {
if (data) {
// @ts-ignore
window[STORE_ACTION_NAME] = data;
}
return data;
};
...
if (isDevMode) {
middleWare(debugName);
}
...
and when I execute action on Server Side I have an error:
ReferenceError: window is not defined
at middleWare (/ssr/node_modules/little-state-machine/dist/little-state-machine.js:125:9)
at Object.updateUserData (/ssr/node_modules/little-state-machine/dist/little-state-machine.js:163:9)
So as soon as i import the dev tool, app crashed with the below message. (state machine works just fine)
I am using a Next.js app, any toughts or suggestions would really help :)
\little-state-machine-devtools\dist\index.js:1
import * as React from 'react';
^^^^^^
SyntaxError: Cannot use import statement outside a module
the problem is with the import statement itself for some reason
import { DevTool } from 'little-state-machine-devtools';
Hey Guys, i am using the little-state-machine to store some data, but the default of the library is to use sessionStorage.
I am trying to change to localStorage but without success, returns error:
e.setItem is not a function
import React from "react";
// Sheets
import "../styles/globals.css";
import "../styles/globals-mobile.css";
import "../styles/bootstrap.min.css";
import { SnackbarProvider } from "notistack";
import { StateMachineProvider, createStore, setStorageType } from "little-state-machine";
createStore(
{
user: null,
oferta: {},
mensagensAgendadas: [],
metricas: {},
},
{
storageType: window.localStorage
}
);
function MyApp({ Component, pageProps }) {
return (
<>
<StateMachineProvider>
<SnackbarProvider maxSnack={3}>
<Component
{...{
...pageProps,
}}
/>
</SnackbarProvider>
</StateMachineProvider>
</>
);
}
export default MyApp;
Hi there
How do I resolve this issue in NextJS with LSM?
Example in NJ:
import { StateMachineProvider, createStore, useStateMachine } from 'little-state-machine';
createStore({
yourDetail: { name: 'Bruce' },
});
function updateName(state, payload) {
return {
...state,
yourDetail: {
...state.yourDetail,
...payload,
},
};
}
function YourComponent() {
const { actions, state } = useStateMachine({ updateName });
return (
<div onClick={() => actions.updateName({ name: 'bill' })}>
{state.yourDetail.name}
</div>
);
}
function MyApp({ Component, pageProps }) {
return (
<StateMachineProvider>
<YourComponent {...pageProps} />
</StateMachineProvider>
)
}
export default MyApp
I am using lsm with react-router for a wizard on a client's site and I need to reset the store when a user returns to the wizard landing page. I found this solution in stack overflow (https://stackoverflow.com/questions/64822032/react-little-state-machine-clear-data) but I cant get it to work. I cant show the full application, but from the below can you see anything wrong with what I have done.
Using
"react-router-dom": "^6.2.1",
"little-state-machine": "^4.2.0",
"little-state-machine-devtools": "^2.0.1",
App.js
createStore({
data
});
function App() {
return (
<StateMachineProvider>
<DevTool />
<div className="container">
...
<Router>
<Steps />
</Router>
</div>
</StateMachineProvider>
);
}
export default App;
Steps.js
....
import { useStateMachine } from "little-state-machine";
import clearAction from "./lsm/actions/clearAction";
...
export default () => {
....
const location = useLocation();
const { state, actions } = useStateMachine({ clearAction });
...
useEffect(() => {
let step = location.pathname.split("/")[2];
// landing page location = http://site.co.uk/wizard
// steps have url = http://site.co.uk/wizard/step[1-4]
if(!step){
actions.clearAction();
}
}, []);
return (...);
};
clearAction.js
export default function clearAction(state, payload) {
return {};
}
I even tried to use window.LSM_RESET(), sessionStorage.removeItem('LSM') and sessionStorage.clear(). None of these work.
Is there a simpler way to reset/clear the store from within a component?
I was using little-state-machine
with react-hook-form
and had some conditional state that I didn't want lsm to remember on load.
The only way I found to implement this was something like this:
const initialState = {/* whatever you want */}
createStore(
{ ...initialState },
{
middleWares: [],
syncStores: {
// you can sync with external store and transform the data
externalStoreName: 'initial',
transform: ({ externalStoreData, currentStoreData }) => {
return {
...initialState,
// here add any other state from external or current
};
}
}
}
);
I actually really like this package a lot and would be happy submitting a PR for what I'm thinking, unless I'm not on the right track.
I don't see how this should currently work, since AsyncStorage is async.... ?
At least I don't know how to make it work in my App. It doesn't restore / or save the data.
Any hints would be helpful. Thank you ❤️
import React from 'react';
import AsyncStorage from '@react-native-community/async-storage';
import {
StateMachineProvider,
createStore,
setStorageType,
} from 'little-state-machine';
import App from './App';
setStorageType(AsyncStorage);
const data: LittleState = {
xFormData: {},
};
createStore(data);
const AppContainer = () => (
<StateMachineProvider>
<App />
</StateMachineProvider>
);
export default AppContainer;
The type that is exported from useStateMachine is Action
export function useStateMachine<T extends Store = Store>(
updateStoreFunction?: UpdateStore,
options?: Options,
): {
action: Action;
actions: Actions;
state: T;
} {
which reflects this type:
export declare type Action = (store: any, payload: any) => any;
export declare type Actions = {
[key: string]: Action;
};
which means that when you use the function action
or functions from the actions
object, it expects both parameters.
change return types to UpdateStoreFunction
:
export declare type UpdateStoreFunction = <T>(payload: T) => T;
in order to reflect usage per documentation.
When cloning the code sample from Code Sanbox (wild-dawn-ud8bq) you have to submit the form twice for the state to update?
Using:
import { GlobalState } from 'little-state-machine'; export function updateFirstLastName( state: GlobalState, payload: { firstname: string; lastname: string; } ) { console.log('state before:', state); console.log('payload:', payload); return { ...state, yourDetails: { ...payload, }, }; }
and
const onSubmit = (data: FormValues) => { actions.updateFirstLastName(data); console.log('state after:', state); };
this shows when changing any field it requires submission twice even when the payload is correct. I hope this is correct how I have gone about this.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.