lemon-state v1.0.0-rc.4
lemon-state
Very simple state manager. No action constants, providers and HOCs, only one function in component. The component updates only when update used properties. Type-safe checked with state types.
install
npm i lemon-state
usage
Create file with initialing of store:
AppStore.js
import { LemonState, createHook } from "lemon-state";
const initialState = {
loading: true, // static data
lang: "ru",
data: [],
computed: (state) => state.data.join(":") // computed data, just use here this state or anoter, all depends will be resolved
};
const actions = {
onSetLoad: (_, payload) => ({
loading: payload
}),
onSwitchLang: ({ getState }, payload) => ({
lang: getState().lang === "ru" ? "en" : "ru"
}),
onAsyncAction: async ({ getState, setState }, payload) => {
setState({ loading: true });
const data = await loadData(payload);
setState({ loading: false, data });
})
};
const config = {
name: "AppStore",
debug: process.env.NODE_ENV === "development" // if we want using redux dev tools
};
export const store = new LemonState(initialState, actions, config); // create store
export const { useStore } = createHook(store); // create hook
initialState
- your first state and this is scheme for autocompletion, write here all properties, object expected
actions
- object with actions, it is scheme for autocompletion too
config
- object with config for debugging
Action expect function with two arguments:
1) StoreChange
- object with four properties for working with store: setState
, getState
and dispatch
:
setState
- update state and rerender all components which used updated (only!) variables
getState
- return actual state
dispatch
- for dispatching another actions
2) payload
- any data for working which you call action
Action function can return plain object, it update state.
LemonState
expect two arguments initialState
, actions
. actions
is not required, but must be object:
class LemonState {
// get actual state
getState: () => State;
// method expect function which be called when state will be updated, return unsubscribe callback
subscribe: (fn) => Unsubscribe;
// after first call subscriber know what properties it using, other call will be only after depends changes
smartSubscribe: (fn) => Unsubscribe;
// set new state, call subscribers only after check different by Object.is algorithm
setState: (diff) => void;
// call action function with StoreChange object
dispatch: (action) => any;
// clear all memory of Store
remove: () => void;
// object with dispatched actions
actions: Actions;
// removed indicator
isRemoved: boolean;
}
useStore
- hook for react component. Return your store with actions. If you once get something property, when it property change component will update.
Loading.js
import React, { memo } from "react";
import { useStore } from "./AppStore";
const Language = memo(() => {
const { lang, onSwitchLang, onSetLoad } = useStore();
console.log("Loading render");
return (
<div>
<button onClick={onSwitchLang}>change language</button>
<button onClick={() => onSetLoad(false)}>change loading</button>
<div>language: {lang}</div>
</div>
);
});
export default Language;
Language.js
import React, { memo } from "react";
import { useStore } from "./AppStore";
const Loading = memo(() => {
const { loading } = useStore(); // if you get 'loading' prop, only this prop will update component
console.log("Language render");
return <div>{loading ? "loading" : "loaded"}</div>;
});
export default Loading;
App.js
import React, { memo } from 'react';
import Language from './Language';
import Loading from './Loading';
export default () => (
<div>
<Language />
<Loading />
</div>
);
See example in CodeSandbox
What we see in console: 1) Components first render:
Language render
Loading render
2) Click to 'Change language' Button, the both components updated, but Loading component doesn't use lang
property. It was because first update of store fire updating all dependent components
In console appended:
Language render
Loading render
3) Click to 'Change language' Button only Language update forever In console appended:
Language render
4) Click to 'change loading' Button only Loading update In console appended:
Loading render
You don't need use constants, HOCs and another verbose patterns. Only one function do all you need: data access and action dispatching
You can use several Stores, like this:
SettingsStore.js
import { LemonState } from "lemon-state";
import { store as appStore } from "./AppStore";
const initialState = {
userSettings
};
const actions = {
onSetSettings: ({ state }, payload) => {
if (!appStore.getState().loading) {
return {
userSettings: payload
};
}
}
};
export const store = LemonState(initialState, actions);
If you use IDE, autocompletion will help you
Typescript
You can use helper Types import { Actions } from 'lemon-state'
. See src/__tests__/TestApp
example.
Debug
You can use redux-devtools-extension
const config = {
name: 'AppStore',
debug: process.env.NODE_ENV === 'development'
};
export const store = store(initialState, actions, config);
5 years ago
5 years ago
5 years ago
5 years ago
6 years ago
6 years ago
6 years ago