Socket
Socket
Sign inDemoInstall

foo-state

Package Overview
Dependencies
4
Maintainers
7
Versions
9
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.2.0 to 1.2.1-rc.2

2

lib/cjs/createGlobalState.d.ts
import { GlobalState, GlobalStateOptions } from "./types";
export declare const createGlobalState: <TState>(initialState: TState | (() => TState), options?: GlobalStateOptions | undefined) => GlobalState<TState>;
export declare const createGlobalState: <TState>(initialState: TState | (() => TState), options?: GlobalStateOptions) => GlobalState<TState>;
import { SetStateAction } from "react";
import { Observable } from "./Observable";
import { SetStateOptions } from "./types";
export declare function createHook<TState>(state$: Observable<TState>, setGlobalState: (state: SetStateAction<TState>, options?: SetStateOptions) => void): () => readonly [TState, (state: SetStateAction<TState>, options?: SetStateOptions | undefined) => void];
export declare function createHook<TState>(state$: Observable<TState>, setGlobalState: (state: SetStateAction<TState>, options?: SetStateOptions) => void): () => readonly [TState, (state: SetStateAction<TState>, options?: SetStateOptions) => void];

@@ -1,5 +0,1 @@

/**
* Inspired by rxjs BehaviorSubject
* https://rxjs.dev/api/index/class/BehaviorSubject
*/
export declare class Observable<TState> {

@@ -10,2 +6,3 @@ private static stateIndex;

private readonly _initializationValue;
private readonly _eventEmitter;
private _value;

@@ -12,0 +9,0 @@ constructor(value: TState);

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Observable = void 0;
/**

@@ -6,4 +11,3 @@ * Inspired by rxjs BehaviorSubject

*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Observable = void 0;
const events_1 = __importDefault(require("events"));
const isBrowser_1 = require("./isBrowser");

@@ -15,2 +19,3 @@ class Observable {

this._value = value;
this._eventEmitter = !(0, isBrowser_1.isBrowser)() ? new events_1.default.EventEmitter() : undefined;
}

@@ -31,2 +36,5 @@ get initializationValue() {

}
else {
this._eventEmitter?.emit(this.eventName);
}
}

@@ -37,2 +45,5 @@ subscribe(subscriber) {

window.addEventListener(eventName, eventListener, Observable.eventOptions);
if (!(0, isBrowser_1.isBrowser)()) {
this._eventEmitter?.addListener(eventName, eventListener);
}
function unsubscribe() {

@@ -39,0 +50,0 @@ window.removeEventListener(eventName, eventListener, Observable.eventOptions);

@@ -35,3 +35,5 @@ "use strict";

const json = (0, safe_stable_stringify_1.default)(value);
this.storage.setItem(this.key, json);
if (json) {
this.storage.setItem(this.key, json);
}
}

@@ -38,0 +40,0 @@ catch (error) {

import { GlobalState, GlobalStateOptions } from "./types";
export declare const createGlobalState: <TState>(initialState: TState | (() => TState), options?: GlobalStateOptions | undefined) => GlobalState<TState>;
export declare const createGlobalState: <TState>(initialState: TState | (() => TState), options?: GlobalStateOptions) => GlobalState<TState>;
import { SetStateAction } from "react";
import { Observable } from "./Observable";
import { SetStateOptions } from "./types";
export declare function createHook<TState>(state$: Observable<TState>, setGlobalState: (state: SetStateAction<TState>, options?: SetStateOptions) => void): () => readonly [TState, (state: SetStateAction<TState>, options?: SetStateOptions | undefined) => void];
export declare function createHook<TState>(state$: Observable<TState>, setGlobalState: (state: SetStateAction<TState>, options?: SetStateOptions) => void): () => readonly [TState, (state: SetStateAction<TState>, options?: SetStateOptions) => void];

@@ -1,5 +0,1 @@

/**
* Inspired by rxjs BehaviorSubject
* https://rxjs.dev/api/index/class/BehaviorSubject
*/
export declare class Observable<TState> {

@@ -10,2 +6,3 @@ private static stateIndex;

private readonly _initializationValue;
private readonly _eventEmitter;
private _value;

@@ -12,0 +9,0 @@ constructor(value: TState);

@@ -5,2 +5,3 @@ /**

*/
import events from "events";
import { isBrowser } from "./isBrowser";

@@ -12,2 +13,3 @@ export class Observable {

this._value = value;
this._eventEmitter = !isBrowser() ? new events.EventEmitter() : undefined;
}

@@ -28,2 +30,5 @@ get initializationValue() {

}
else {
this._eventEmitter?.emit(this.eventName);
}
}

@@ -34,2 +39,5 @@ subscribe(subscriber) {

window.addEventListener(eventName, eventListener, Observable.eventOptions);
if (!isBrowser()) {
this._eventEmitter?.addListener(eventName, eventListener);
}
function unsubscribe() {

@@ -36,0 +44,0 @@ window.removeEventListener(eventName, eventListener, Observable.eventOptions);

@@ -29,3 +29,5 @@ /* eslint-disable no-console */

const json = stringify(value);
this.storage.setItem(this.key, json);
if (json) {
this.storage.setItem(this.key, json);
}
}

@@ -32,0 +34,0 @@ catch (error) {

{
"name": "foo-state",
"version": "1.2.0",
"version": "1.2.1-rc.2",
"description": "A simple yet powerful library for managing global states with react",

@@ -62,15 +62,15 @@ "main": "./lib/cjs/index.js",

"@testing-library/react": "^13.0.0",
"@types/jest": "^27.4.0",
"@types/jest": "^29.2.0",
"@types/react": "^18.0.0",
"@typescript-eslint/eslint-plugin": "^5.11.0",
"@typescript-eslint/parser": "^5.11.0",
"babel-jest": "^28.0.2",
"babel-jest": "^29.0.0",
"eslint": "^8.8.0",
"eslint-config-prettier": "^8.1.0",
"eslint-import-resolver-typescript": "^2.5.0",
"eslint-import-resolver-typescript": "^3.1.2",
"eslint-plugin-import": "^2.25.2",
"eslint-plugin-react": "^7.28.0",
"eslint-plugin-react-hooks": "^4.3.0",
"jest": "^28.0.2",
"jest-environment-jsdom": "^28.0.2",
"jest": "^29.2.2",
"jest-environment-jsdom": "^29.0.0",
"jest-localstorage-mock": "^2.4.18",

@@ -82,3 +82,3 @@ "prettier": "^2.2.1",

"semantic-release": "^19.0.2",
"typedoc": "^0.22.11",
"typedoc": "^0.23.2",
"typedoc-plugin-markdown": "^3.11.13",

@@ -85,0 +85,0 @@ "typescript": "^4.5.5"

[![build](https://github.com/foobaragency/react-global-state/actions/workflows/build.yml/badge.svg)](https://github.com/foobaragency/react-global-state/actions/workflows/build.yml)
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-7-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
![Total coverage](./badges/coverage-jest%20coverage.svg)

@@ -9,2 +12,17 @@ # foo-state

## Table of contents
1. [Installation](#⚙️-installation)
2. [Examples](#🔌-examples)
1. [Using as a hook](#1---using-as-a-hook)
2. [Using outside React](#2---using-outside-react)
3. [Partial state hook](#3---partial-state-hook)
4. [Persist state](#4---persist-state)
5. [Using deep comparison](#5---using-deep-comparison-useful-for-objects-and-arrays-to-prevent-unnecessary-re-renders)
6. [With lazy initialization](#6---with-lazy-initialization)
7. [Using with TypeScript](#7---with-typescript)
3. [API Reference](#api-reference)
4. [Contributing](#👥-contributing)
5. [License](#🏛-license)
## ⚙️ Installation

@@ -16,231 +34,330 @@

## 🔌 Usage
## 🔌 Examples
### Example 1 - using as a hook
```jsx
import { createGlobalState } from "foo-state"
### 1 - using as a hook
<details>
<summary>See code</summary>
const initialState = 0
```jsx
import { createGlobalState } from "foo-state"
const { useGlobalState } = createGlobalState(initialState)
const initialState = 0
const Counter = () => {
const [count, setCount] = useGlobalState()
const { useGlobalState } = createGlobalState(initialState)
const increment = () => {
setCount(count + 1)
const Counter = () => {
const [count, setCount] = useGlobalState()
const increment = () => {
setCount(count + 1)
}
const decrement = () => {
// you can also use callback functions
setCount((state) => {
if (state > 0) {
return state - 1
}
return state
})
}
return (
<div>
<button onClick={decrement}>-</button>
<span>{count}</span>
<button onClick={increment}>+</button>
</div>
)
}
```
</details>
const decrement = () => {
// you can also use callback functions
setCount((state) => {
if (state > 0) {
return state - 1
}
### 2 - using outside react
return state
})
<details>
<summary>See code</summary>
```jsx
import { createGlobalState } from "foo-state"
const initialState = 0
const { useGlobalState, setGlobalState } = createGlobalState(initialState)
function setInitialState() {
setTimeout(() => {
setGlobalState(10_000)
}, 2_000)
}
return (
<div>
<button onClick={decrement}>-</button>
<span>{count}</span>
<button onClick={increment}>+</button>
</div>
)
}
```
const Counter = () => {
const [count, setCount] = useGlobalState()
### Example 2 - using outside react
useEffect(() => {
setInitialState()
}, [])
```jsx
import { createGlobalState } from "foo-state"
const decrement = () => {
setCount(count - 1)
}
const initialState = 0
const increment = () => {
setCount(count + 1)
}
const { useGlobalState, setGlobalState } = createGlobalState(initialState)
return (
<div>
<button onClick={decrement}>-</button>
<span>{count}</span>
<button onClick={increment}>+</button>
</div>
)
}
```
</details>
function setInitialState() {
setTimeout(() => {
setGlobalState(10_000)
}, 2_000)
}
### 3 - partial state hook
const Counter = () => {
const [count, setCount] = useGlobalState()
<details>
<summary>See code</summary>
useEffect(() => {
setInitialState()
}, [])
```jsx
import { createGlobalState } from "foo-state"
const decrement = () => {
setCount(count - 1)
const initialState = {
firstName: "John",
lastName: "Doe",
age: 43
}
const increment = () => {
setCount(count + 1)
const { createPartialState } = createGlobalState(initialState)
const useAge = createPartialState(state => state.age)
const Age = () => {
const age = useAge()
return (
<div>{age}</div>
)
}
```
</details>
return (
<div>
<button onClick={decrement}>-</button>
<span>{count}</span>
<button onClick={increment}>+</button>
</div>
)
}
```
### 4 - persist state
### Example 3 - Partial state hook
```jsx
import { createGlobalState } from "foo-state"
<details>
<summary>See code</summary>
const initialState = {
```jsx
import { createGlobalState } from "foo-state"
const initialState = {
firstName: "John",
lastName: "Doe",
age: 43
}
const { useGlobalState } = createGlobalState(initialState, {
persistence: {
key: "x-storage-key",
// optional, defaults to localStorage
// localStorage or sessionStorage
type: "localStorage",
}
})
const Person = () => {
const [person, setPerson] = useGlobalState()
function onChange(e){
const {name, value} = e.target
setPerson({
...person,
[name]: value
})
}
return (
<div>
<label>
First Name
<br />
<input name="firstName" value={person.firstName} onChange={onChange} />
</label>
<label>
Last Name
<br />
<input name="lastName" value={person.lastName} onChange={onChange} />
</label>
<label>
Age
<br />
<input name="age" value={person.age} onChange={onChange} />
</label>
</div>
)
}
```
</details>
### 5 - using deep comparison (useful for objects and arrays to prevent unnecessary re-renders)
<details>
<summary>See code</summary>
```jsx
import { createGlobalState } from "foo-state"
const initialState = {
firstName: "John",
lastName: "Doe",
age: 43
}
age: 43,
}
const { createPartialState } = createGlobalState(initialState)
const { useGlobalState } = createGlobalState(initialState)
const useAge = createPartialState(state => state.age)
const Profile = () => {
const [state, setState] = useGlobalState()
const Age = () => {
const age = useAge()
function invertNames() {
const newState = {
firstName: "Doe",
lastName: "John",
age: 43,
}
setState(newState, { deepCompare: true })
}
return (
<div>{age}</div>
<div>
<p>First Name: {state.firstName}</p>
<p>Last Name: {state.lastName}</p>
<p>Age: {state.age}</p>
<button onClick={invertNames}>Click me!</button>
</div>
)
}
```
}
```
</details>
### Example 4 - Persist state
```jsx
import { createGlobalState } from "foo-state"
### 6 - With lazy initialization
const initialState = {
firstName: "John",
lastName: "Doe",
age: 43
}
<details>
<summary>See code</summary>
const { useGlobalState } = createGlobalState(initialState, {
persistence: {
key: "x-storage-key",
// optional, defaults to localStorage
// localStorage or sessionStorage
type: "localStorage",
```jsx
function heavyCalculation() {
const user = {
name: 'John',
birthday: new Date('1995-03-15')
}
// let's pretend we're getting a correct age here
const age = new Date().getFullYear() - user.birthday.getFullYear()
return {
name: user.name,
age,
}
}
})
const Person = () => {
const [person, setPerson] = useGlobalState()
function onChange(e){
const {name, value} = e.target
const {useGlobalState} = createGlobalState(heavyCalculation)
setPerson({
...person,
[name]: value
})
}
const Profile = () => {
const [state] = useGlobalState()
return (
<div>
<label>
First Name
<br />
<input name="firstName" value={person.firstName} onChange={onChange} />
</label>
<label>
Last Name
<br />
<input name="lastName" value={person.lastName} onChange={onChange} />
</label>
<label>
Age
<br />
<input name="age" value={person.age} onChange={onChange} />
</label>
</div>
<div>
<p>Name: {state.name}</p>
<p>Age: {state.age}</p>
</div>
)
}
```
}
```
</details>
## Example 5 - Using deep comparison (useful for objects and arrays to prevent unnecessary re-renders)
```jsx
import { createGlobalState } from "foo-state"
### 7 - With typescript
const initialState = {
firstName: "John",
lastName: "Doe",
age: 43,
}
<details>
<summary>See code</summary>
const { useGlobalState } = createGlobalState(initialState)
```tsx
import { createGlobalState } from "foo-state"
const Profile = () => {
const [state, setState] = useGlobalState()
type Person = {
firstName: string
lastName: string
age: number
}
function invertNames() {
const newState = {
firstName: "Doe",
lastName: "John",
age: 43,
}
setState(newState, { deepCompare: true })
const { useGlobalState } = createGlobalState<Person>({
firstName: "John",
lastName: "Doe",
// string is not assignable to type number
age: "43"
})
const Profile = () => {
const [state, setState] = useGlobalState()
function invertNames() {
const newState = {
firstName: "Doe",
lastName: "John",
age: 43,
}
setState(newState, {deepCompare: true})
}
return (
<div>
<p>First Name: {state.firstName}</p>
<p>Last Name: {state.lastName}</p>
<p>Age: {state.age}</p>
<button onClick={invertNames}>Click me!</button>
</div>
)
}
```
</details>
return (
<div>
<p>First Name: {state.firstName}</p>
<p>Last Name: {state.lastName}</p>
<p>Age: {state.age}</p>
<button onClick={invertNames}>Click me!</button>
</div>
)
}
```
## API Reference
## Example 6 - With typescript
```tsx
import { createGlobalState } from "foo-state"
### createGlobalState
type Person = {
firstName: string
lastName: string
age: number
}
```ts
createGlobalState<S>(initialState: S | () => S, options: GlobalStateOptions): GlobalState
```
const { useGlobalState } = createGlobalState<Person>({
firstName: "John",
lastName: "Doe",
// string is not assignable to type number
age: "43"
})
This is, most probably, the only function you will need to use from this library.
#### Params
The initial state can be either a `value` or a `function` that resolves to a value. This mirrors the [`useState` API](https://reactjs.org/docs/hooks-reference.html#usestate).
const Profile = () => {
const [state, setState] = useGlobalState()
The library tries to infer the type as much as possible, but you can also specify the type:
function invertNames() {
const newState = {
firstName: "Doe",
lastName: "John",
age: 43,
}
setState(newState, {deepCompare: true})
}
```ts
type Person = {}
return (
<div>
<p>First Name: {state.firstName}</p>
<p>Last Name: {state.lastName}</p>
<p>Age: {state.age}</p>
<button onClick={invertNames}>Click me!</button>
</div>
)
}
const state = createGlobalState<Person>({})
```
You can always [read more about the `options` parameter for `createGlobalState`](./docs/interfaces/GlobalStateOptions.md).
#### Returned functions
+ `useGlobalState` - This react hook can be used inside any functional component to access or change the state.
+ `useReadOnlyState` - This react hook doesn't give you access to the `setState` function, instead it only returns the current state.
+ `createPartialState` - This function will return a read only react hook with a custom partial state. [See example of `createPartialState`](#3---partial-state-hook)
+ `getGlobalState` - This function returns the current state and can be used anywhere in you application, not only inside react components.[See example of `getGlobalState`](#2---using-outside-react)
+ `setGlobalState` - This function allows you to change the state and can be used anywhere in you application, not only inside react components.[See example of `setGlobalState`](#2---using-outside-react)
## 👥 Contributing

@@ -255,1 +372,26 @@

[MIT](https://choosealicense.com/licenses/mit/)
## Contributors ✨
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tr>
<td align="center"><a href="https://github.com/n4bb12"><img src="https://avatars.githubusercontent.com/u/6810177?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Abraham Schilling</b></sub></a><br /><a href="#design-n4bb12" title="Design">🎨</a> <a href="#mentoring-n4bb12" title="Mentoring">🧑‍🏫</a> <a href="https://github.com/foobaragency/foo-state/commits?author=n4bb12" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/kaiserbock"><img src="https://avatars.githubusercontent.com/u/730195?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Daniel Bock</b></sub></a><br /><a href="#design-kaiserbock" title="Design">🎨</a> <a href="https://github.com/foobaragency/foo-state/commits?author=kaiserbock" title="Code">💻</a></td>
<td align="center"><a href="https://leniac.dev"><img src="https://avatars.githubusercontent.com/u/7433159?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Lenilson "Lenny" Nascimento</b></sub></a><br /><a href="https://github.com/foobaragency/foo-state/commits?author=l-Leniac-l" title="Code">💻</a> <a href="https://github.com/foobaragency/foo-state/commits?author=l-Leniac-l" title="Documentation">📖</a> <a href="#maintenance-l-Leniac-l" title="Maintenance">🚧</a></td>
<td align="center"><a href="https://github.com/afennert"><img src="https://avatars.githubusercontent.com/u/33861227?v=4?s=100" width="100px;" alt=""/><br /><sub><b>afennert</b></sub></a><br /><a href="https://github.com/foobaragency/foo-state/commits?author=afennert" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Segebre"><img src="https://avatars.githubusercontent.com/u/10774915?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Juan Enrique Segebre Zaghmout</b></sub></a><br /><a href="https://github.com/foobaragency/foo-state/commits?author=segebre" title="Code">💻</a> <a href="#maintenance-segebre" title="Maintenance">🚧</a> <a href="https://github.com/foobaragency/foo-state/commits?author=segebre" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/seanowenhayes"><img src="https://avatars.githubusercontent.com/u/3706358?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sean Hayes</b></sub></a><br /><a href="https://github.com/foobaragency/foo-state/commits?author=seanowenhayes" title="Documentation">📖</a> <a href="https://github.com/foobaragency/foo-state/commits?author=seanowenhayes" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/seblondono"><img src="https://avatars.githubusercontent.com/u/20850740?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sebastian Londono</b></sub></a><br /><a href="https://github.com/foobaragency/foo-state/pulls?q=is%3Apr+reviewed-by%3Aseblondono" title="Reviewed Pull Requests">👀</a> <a href="#ideas-seblondono" title="Ideas, Planning, & Feedback">🤔</a></td>
</tr>
</table>
<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!

@@ -5,5 +5,5 @@ /**

*/
import events from "events"
import { isBrowser } from "./isBrowser"
export class Observable<TState> {

@@ -20,2 +20,3 @@ private static stateIndex = 0

private readonly _initializationValue: TState
private readonly _eventEmitter: events.EventEmitter | undefined
private _value: TState

@@ -26,2 +27,3 @@

this._value = value
this._eventEmitter = !isBrowser() ? new events.EventEmitter() : undefined
}

@@ -46,2 +48,4 @@

window.dispatchEvent(new Event(this.eventName))
} else {
this._eventEmitter?.emit(this.eventName)
}

@@ -56,2 +60,6 @@ }

if (!isBrowser()) {
this._eventEmitter?.addListener(eventName, eventListener)
}
function unsubscribe() {

@@ -58,0 +66,0 @@ window.removeEventListener(

@@ -33,3 +33,5 @@ /* eslint-disable no-console */

const json = stringify(value)
this.storage.setItem(this.key, json)
if (json) {
this.storage.setItem(this.key, json)
}
} catch (error) {

@@ -36,0 +38,0 @@ console.error(error)

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc