Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

easy-react-state

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

easy-react-state - npm Package Compare versions

Comparing version 1.0.1 to 1.0.2

70

dist/index.es.js

@@ -1284,53 +1284,31 @@ import React from 'react';

var store = createStore(configStore, options);
var useSelector = function (selector, computationFn) {
var state = React.useRef(store.getState());
var _a = __read(React.useState({}), 2), _ = _a[0], forceRender = _a[1];
var prevSelectedState = React.useRef();
var computedValue = React.useMemo(function () {
prevSelectedState.current = selector(state.current);
if (computationFn) {
return computationFn(prevSelectedState.current);
var useSelector = function (selector, equalityFn) {
if (equalityFn === void 0) { equalityFn = Object.is; }
var _a = __read(React.useState({}), 2), forceRender = _a[1];
var prevSelectedState = React.useRef({});
var latestSelector = React.useRef();
// Computing the selector. If selector reference was not changed upon rendering,
// then cached value is returned.
try {
if (selector !== latestSelector.current) {
prevSelectedState.current = selector(store.getState());
latestSelector.current = selector;
}
return prevSelectedState.current;
// We need to run the computation if the dummy `-` state was changed.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [_, computationFn, selector]);
React.useEffect(function () {
}
catch (err) {
var errorMessage = "An error occured while selecting the store state: " + err.message + ".";
throw new Error(errorMessage);
}
React.useEffect(function subscribeToStore() {
var unsubscribe = store.subscribe(function () {
var nextState = store.getState();
var nextSelectedState = selector(nextState);
// NOTE: If there is changes on the selected state, we need to re-render the Component
// via updating a state because we want to have a re-computation which will run
// in next render in `React.useMemo` above.
if (Array.isArray(prevSelectedState.current) &&
!Object.is(prevSelectedState.current, nextSelectedState)) {
state.current = nextState;
var nextSelectedState = latestSelector.current(nextState);
if (!equalityFn(prevSelectedState.current, nextSelectedState)) {
prevSelectedState.current = nextSelectedState;
forceRender({});
}
// If object, we gonna use `shallowEqual` to check if the top-level keys of the 2 objects
// are the same.
else if (typeof prevSelectedState.current === 'object' &&
typeof nextSelectedState === 'object') {
var prevSelectedStateSize = Object.keys(prevSelectedState.current)
.length;
var nextSelectedStateSize = Object.keys(nextSelectedState).length;
if ((prevSelectedStateSize === 0 &&
!Object.is(prevSelectedState.current, nextSelectedState)) ||
// If the sizes are not equal, means that the properties are changed. Needs to re-compute
(prevSelectedStateSize !== nextSelectedStateSize ||
!shallowEqual(prevSelectedState.current, nextSelectedState))) {
state.current = nextState;
forceRender({});
}
}
// If primitives like number, string, boolean
else {
if (!Object.is(prevSelectedState.current, nextSelectedState)) {
state.current = nextState;
forceRender({});
}
}
});
return function () { return unsubscribe(); };
}, [computedValue, selector]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
/**

@@ -1342,3 +1320,3 @@ * `useSelector` will return a conditional type. If `computationFn` is undefined, it should

*/
return computedValue;
return prevSelectedState.current;
};

@@ -1349,3 +1327,3 @@ return [useSelector, store.setters, store];

export default createStateManager;
export { NOTHING as nothing };
export { shallowEqual };
//# sourceMappingURL=index.es.js.map

@@ -1290,53 +1290,31 @@ 'use strict';

var store = createStore(configStore, options);
var useSelector = function (selector, computationFn) {
var state = React.useRef(store.getState());
var _a = __read(React.useState({}), 2), _ = _a[0], forceRender = _a[1];
var prevSelectedState = React.useRef();
var computedValue = React.useMemo(function () {
prevSelectedState.current = selector(state.current);
if (computationFn) {
return computationFn(prevSelectedState.current);
var useSelector = function (selector, equalityFn) {
if (equalityFn === void 0) { equalityFn = Object.is; }
var _a = __read(React.useState({}), 2), forceRender = _a[1];
var prevSelectedState = React.useRef({});
var latestSelector = React.useRef();
// Computing the selector. If selector reference was not changed upon rendering,
// then cached value is returned.
try {
if (selector !== latestSelector.current) {
prevSelectedState.current = selector(store.getState());
latestSelector.current = selector;
}
return prevSelectedState.current;
// We need to run the computation if the dummy `-` state was changed.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [_, computationFn, selector]);
React.useEffect(function () {
}
catch (err) {
var errorMessage = "An error occured while selecting the store state: " + err.message + ".";
throw new Error(errorMessage);
}
React.useEffect(function subscribeToStore() {
var unsubscribe = store.subscribe(function () {
var nextState = store.getState();
var nextSelectedState = selector(nextState);
// NOTE: If there is changes on the selected state, we need to re-render the Component
// via updating a state because we want to have a re-computation which will run
// in next render in `React.useMemo` above.
if (Array.isArray(prevSelectedState.current) &&
!Object.is(prevSelectedState.current, nextSelectedState)) {
state.current = nextState;
var nextSelectedState = latestSelector.current(nextState);
if (!equalityFn(prevSelectedState.current, nextSelectedState)) {
prevSelectedState.current = nextSelectedState;
forceRender({});
}
// If object, we gonna use `shallowEqual` to check if the top-level keys of the 2 objects
// are the same.
else if (typeof prevSelectedState.current === 'object' &&
typeof nextSelectedState === 'object') {
var prevSelectedStateSize = Object.keys(prevSelectedState.current)
.length;
var nextSelectedStateSize = Object.keys(nextSelectedState).length;
if ((prevSelectedStateSize === 0 &&
!Object.is(prevSelectedState.current, nextSelectedState)) ||
// If the sizes are not equal, means that the properties are changed. Needs to re-compute
(prevSelectedStateSize !== nextSelectedStateSize ||
!shallowEqual(prevSelectedState.current, nextSelectedState))) {
state.current = nextState;
forceRender({});
}
}
// If primitives like number, string, boolean
else {
if (!Object.is(prevSelectedState.current, nextSelectedState)) {
state.current = nextState;
forceRender({});
}
}
});
return function () { return unsubscribe(); };
}, [computedValue, selector]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
/**

@@ -1348,3 +1326,3 @@ * `useSelector` will return a conditional type. If `computationFn` is undefined, it should

*/
return computedValue;
return prevSelectedState.current;
};

@@ -1355,3 +1333,3 @@ return [useSelector, store.setters, store];

exports.default = createStateManager;
exports.nothing = NOTHING;
exports.shallowEqual = shallowEqual;
//# sourceMappingURL=index.js.map
{
"name": "easy-react-state",
"version": "1.0.1",
"version": "1.0.2",
"description": "Fun to use state management library for your awesome React app",

@@ -19,2 +19,3 @@ "author": "ombori",

"build": "rollup -c",
"build:tsc": "npx tsc --declaration src/index.tsx",
"start": "rollup -c -w",

@@ -21,0 +22,0 @@ "prepare": "yarn run build",

# easy-react-state
> Fun to use state management library for your awesome React app
Managing your app state should be easy and fun. `easy-react-state` is a minimal library
for creating state management for your React project.
[![NPM](https://img.shields.io/npm/v/easy-react-state.svg)](https://www.npmjs.com/package/easy-react-state) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
[![NPM](https://img.shields.io/npm/v/easy-react-state.svg)](https://www.npmjs.com/package/easy-react-state)

@@ -11,6 +12,194 @@ ## Install

npm install --save easy-react-state
or
yarn add easy-react-state
```
## Features
- easy to adopt with. Just think of `React.useState` where it has multiple setters which
update the state object.
- reduce boilerplate codes. No need to create actions. Just call and pass the right data.
- intuitive selector system.
- minimal API. Don't need to use some helper functions to support async updates.
- typescript supports.
## Usage
### 1 - Configuring your store
```jsx
const configAppStore = {
todos: {
initialState: [],
setters: state => ({
addTodo(todo) {
state.push(todo)
return state
},
}),
},
}
```
### 2 - Creating state manager based on your store
```jsx
const [useAppSelector, appSetters] = createStateManager(configAppStore)
```
### 3 - Consume to your React Component
We don't need a `Provider` to consume the store. Just create a manager, then you can use it directly.
```jsx
const App = () => {
const todos = useAppSelector(state => state.todos)
console.log('todos', todos)
return (
<div>
<h3>Todos Control</h3>
<button
onClick={() => {
const todo = {
id: `todo-${Date.now()}`,
label: `Todo ${Date.now()}`,
}
appSetters.todos.addTodo(todo)
}}
>
Add todo
</button>
</div>
)
}
```
## Use setters inside async
Our setters are object which holds all the state setters. Upon creating, we can call setters just like normal functions. Indeed, we can call it everywhere. No need wrapper function like `thunk` to make it possible. Just call it immediately!
```jsx
const [useAppSelector, appSetters] = createStateManager(configAppStore)
async function fetchUsers() {
appSetters.users.loading()
try {
const res = await apiUsers()
appSetters.users.setUsers(res)
} catch (err) {
appSetters.users.setError(err)
}
}
```
## Invoking setters outside React
React will batch the updates for subsequent calls of setters. But if you call these setters outside the React event system, like `Promise` or `setTimeout`, then every call will cause a re-render to Component. To avoid this, you can wrap your setters inside the `ReactDOM.unstable_batchedUpdates`.
```jsx
import { unstable_batchedUpdates as batch } from 'react-dom'
// No batching
const Test1 = () => {
React.useEffect(() => {
// This will cause 2 renders
setTimeout(() => {
obj1.setter1()
obj2.setter2()
})
}, [])
return <div>Test 1</div>
}
// With batching
const Test2 = () => {
React.useEffect(() => {
setTimeout(() => {
// Single render
batch(() => {
obj1.setter1()
obj2.setter2()
})
})
}, [])
return <div>Test 2</div>
}
```
## API
#### Type Interfaces
```tsx
interface CreateState<S = any> {
initialState: S
setters: (state: S) => any
}
interface ConfigStore {
[x: string]: CreateState
}
interface Options {
label?: string
logging?: boolean
}
interface Store<S, U> {
getState: () => S
subscribe: (Listener: Listener) => () => void
setters: U
}
interface Selector<S> {
<T>(
selector: (state: S) => T,
equalityFn?: (prevSelectedState: T, nextSelectedState: T) => boolean,
): T
}
interface Setter {
(...args: any[]): any
}
```
#### createStateManager
```tsx
createStateManager(configStore: ConfigStore, options?: Options): [useSelector, setters, store]
```
This function creates a resources which we can use to manage the state based on the `configStore`. It also return a store object.
#### store
```tsx
store: Store<State, Setters>
```
An object which we can use to get the current state, subscribe and update state through setters. Its interface is just like `redux-store`.
#### useSelector
```tsx
useSelector(selector: Selector): selectedState
```
A function which we can use to extract data from the store state using a selector function.
`useSelector` semantics are pretty the same with `useSelector` of react-redux. The difference
is `useSelector` of react-redux uses strict `===` reference equality. Unlike `useSelector` of easy-react-state, it uses `Object.is` for comparing `selectedState`. [Check react-redux for more info](https://react-redux.js.org/api/hooks#useselector). `useSelector` supports the selector created by [reselect](https://github.com/reduxjs/reselect).
#### setters
```tsx
setter(...args: any[]): void
```
An object which holds functions which we can use to update the state.
## Cons
- doesnt have DevTools for now. But it has logging option.
- it doesnt support nested state. All state are resided at the top level object.
## License

@@ -17,0 +206,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc