All Projects → sahabpardaz → react-store

sahabpardaz / react-store

Licence: MIT License
A library for better state management in react hooks world

Programming Languages

typescript
32286 projects
javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to react-store

niue
A tiny shared state and event library for React
Stars: ✭ 17 (-50%)
Mutual labels:  state-management, react-hooks
east-store
east-store is a state manager with easiest api that based hooks and immer.
Stars: ✭ 18 (-47.06%)
Mutual labels:  state-management, react-hooks
react-without-redux
React State Management without Redux
Stars: ✭ 33 (-2.94%)
Mutual labels:  state-management, react-hooks
rex-state
Convert hooks into shared states between React components
Stars: ✭ 32 (-5.88%)
Mutual labels:  state-management, react-hooks
atomic-state
A decentralized state management library for React
Stars: ✭ 54 (+58.82%)
Mutual labels:  state-management, react-hooks
react-immer
No nonsense state management with Immer and React hooks
Stars: ✭ 13 (-61.76%)
Mutual labels:  state-management, react-hooks
react-cool-form
😎 📋 React hooks for forms state and validation, less code more performant.
Stars: ✭ 246 (+623.53%)
Mutual labels:  state-management, react-hooks
use-state-machine
Use Finite State Machines with React Hooks
Stars: ✭ 28 (-17.65%)
Mutual labels:  state-management, react-hooks
concave
🧐 Lens-like state management (for React).
Stars: ✭ 13 (-61.76%)
Mutual labels:  state-management, react-hooks
use-app-state
🌏 useAppState() hook. that global version of setState() built on Context.
Stars: ✭ 65 (+91.18%)
Mutual labels:  state-management, react-hooks
Easy Peasy
Vegetarian friendly state for React
Stars: ✭ 4,525 (+13208.82%)
Mutual labels:  state-management, react-hooks
jedisdb
redis like key-value state management solution for React
Stars: ✭ 13 (-61.76%)
Mutual labels:  state-management, react-hooks
Constate
React Context + State
Stars: ✭ 3,519 (+10250%)
Mutual labels:  state-management, react-hooks
react-mlyn
react bindings to mlyn
Stars: ✭ 19 (-44.12%)
Mutual labels:  state-management, react-hooks
use-simple-store
🏬 Simple state management using React Hook
Stars: ✭ 21 (-38.24%)
Mutual labels:  state-management, react-hooks
resynced
An experimental hook that lets you have multiple components using multiple synced states using no context provider
Stars: ✭ 19 (-44.12%)
Mutual labels:  state-management, react-hooks
use-query-string
🆙 A React hook that serializes state into the URL query string
Stars: ✭ 50 (+47.06%)
Mutual labels:  state-management, react-hooks
hookstore
Hook based and lightweight centralized state management for React.
Stars: ✭ 28 (-17.65%)
Mutual labels:  state-management, react-hooks
window-scroll-position
React hook for Window scroll position
Stars: ✭ 81 (+138.24%)
Mutual labels:  react-hooks
react-social-network
react social network
Stars: ✭ 13 (-61.76%)
Mutual labels:  react-hooks

React Store

React Store is a library for better state management in react hooks new world.

It facilitates to split components into smaller and maintainable ones then share States between them. It also covers shortcomings of react hooks (believe me!) and let developers to use classes to manage their components logic and using it's IOC container.
The ability to separate components logics and jsx is one of other benefits of this library.

Table of content

Installation

First install core library:

yarn add @react-store/core

Then enable decorators in typescript:

{
  "compilerOptions": {
    "experimentalDecorators": true,
}

You can also use other javascript transpilers such as babel.

Usage

Now it's ready. First create a Store:

// user.store.ts
import { Store } from "@react-store/core";

@Store()
export class UserStore {
  name: string;

  onNameChange(e: ChangeEvent) {
    this.name = e.target.value;
  }
}

Then connect it to the component Tree by using connect:

// App.tsx
import { connect, useStore } from "@react-store/core";

interface Props {
  p1: string;
}

export const App = connect((props: Props) => {
  const st = useStore(UserStore);
  return (
    <div>
      {st.name}
      <Input />
    </div>
  );
}, UserStore);

And enjoy to use store in child components by useStore hook. pass Store Class as first parameter:

import { useStore } from "@react-store/core";

export function Input() {
  const st = useStore(UserStore);
  return (
    <div>
      <span>Name is: </span>
      <input onChange={st.onNameChange} />
    </div>
  );
}

Effects

You can manage side effects with @Effect() decorator. Like react dependency array you must define array of dependencies.
For clear effects again like React useEffect you can return a function from methods which is decorated with @Effect.

@Store()
export class UserStore {
  name: string;

  @Effect((_: UserStore) => [_.name])
  nameChanged() {
    console.log("name changed to:", this.name);

    return () => console.log("Clear Effect");
  }
}

You can also pass object as dependency with deep equal mode. just pass true as second parameters:

@Store()
export class UserStore {
  user = { name: "" };

  @Effect<UserStore>((_) => [_.user], true)
  usernameChanged() {
    console.log("name changed to:", this.name);
  }
}

Instead of passing a function to effect to detect dependencies you can pass an array of strings or just one string.
The string can be an object path to define dependencies:

@Store()
export class UserStore {
  user = { name: "" };

  @Effect(["user.name"])
  usernameChanged() {}

  @Effect("user", true)
  userChanged() {}
}

Methods which decorate with @Effect() can be async, but if you want to return clear effect function make it sync method

Auto Effect

With @AutoEffect() like @Effect() you can manage your application side effects. With this decorator, dependencies will calculate automatically base on store properties you have used.

For example:

@Store()
export class UserStore {
  a = 1;
  
  b = 2;

  user = { name: "" };

  @AutoEffect()
  autoEffect() {
    this.a = 1;
    this.b = this.a;
    const username = this.user.name
  }
}

The dependencies for autoEffect method is user.name.

Props

To have store parent component props (the component directly connected to store by using connect) inside store class use @Props():

// user.store.ts
import type { Props as AppProps } from "./App";
import { Props, Store } from "@react-store/core";

@Store()
export class UserStore {
  @Props()
  props: AppProps;
}

Store Part

Store Part like store is a class which is decorated with @StorePart() and can only be connected to a store with @Wire() decorator.

@StorePart()
class Validator {
  object: Record<string, unknown>;

  hasError = false;

  @Effect("object", true)
  validate() {
    this.hasError = someValidator(object).hasError;
  }
}

@Store()
class UserForm {
  user: User;

  @Wire(Validator)
  validator: Validator;

  @Effect([])
  onMount() {
    this.validator.object = this.user;
  }

  onUsernameChange(username) {
    this.user.username = username;
  }
}
  • Store part can not be used directly with useStore and must be wired to a store.
  • Like store, store part can have it's effects, dependency injection.
  • Store part is piece of logics and states can be wired to any other store and play a role like React custom hooks

Computed Property

You can define getter in store class and automatically it will be a computed value. it means that if any underlying class properties which is used in getter change, we will recompute getter value and cache it.

@Store()
class BoxStore {
  width: number;

  height: number;

  get area() {
    return (this.width + this.height) * 2;
  }
}

Dependency Injection

In this library we have also supported dependency injection. To define Injectables, decorate class with @Injectable():

@Injectable()
class UserService {}

In order to inject dependencies into injectable, use @Inject(...):

@Injectable()
@Inject(AuthService, UserService)
class PostService {
  constructor(private authService: AuthService, private userService: UserService) {}
}

Also you can use @Inject() as parameter decorator:

@Injectable()
@Inject(AuthService)
class PostService {
  constructor(
    private authService: AuthService,
    @Inject(UserService) private userService: UserService
  ) {}
}

Injection works fine for stores. Injectable can be injected into all stores. Also stores can be injected into other stores but there is one condition. For example, you want to inject A store into B store so the component which is wrapped with connect(..., A) must be higher in B store parent component. In other words, it works like React useContext rule.

@Injectable()
@Inject(AlertsStore)
class UserStore {
  constructor(private alertsStore: AlertsStore) {}
}

Store property & method

  • Property: Each store property can act like piece of component state and mutating their values will rerender all store users as react context API works. Also in more precise way you can declare dependencies for each user of store to prevent additional rendering and optimization purposes. we will talk about more.

  • Method: Store methods like Redux actions uses for state mutations. A good practice is to write logics and state mutation codes inside store class methods and use them in components. as you will guess directly mutating state from components will be a bad practice. Store methods are bound to store class instance by default. feel free to use them like below:

function Input() {
  const st = useStore(UserStore);
  return <input onChange={st.onNameChange} />;
}
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].