Giter VIP home page Giter VIP logo

reatom's Introduction

Reatom is the ultimate state manager with quite unique set of features, it provides the most modern techniques for describing, executing, and debugging code in a tiny package. It is an opinionated data manager with strict, but flexible rules, which allows you to write simple and maintainable code.

Key principles are immutability and explicit reactivity (no proxies), implicit DI and actor-like lifecycle hooks. All this with simple API and automatic type inference.

The core package includes all these features and you may use it anywhere, from huge apps to even small libs, as the overhead is only 2 KB. Also, you could reuse our carefully written helper tools to solve complex tasks in a couple lines of code. We are trying to build a stable and balanced ecosystem for perfect DX and predictable maintains even for years ahead.

Do you use React.js? Check out npm-react package!

Simple example

Install

npm i @reatom/core

vanilla repl

react repl

import { action, atom, createCtx } from '@reatom/core'

// primitive mutable atom
const inputAtom = atom('')
// computed readonly atom
// `spy` reads the atom and subscribes to it
const greetingAtom = atom((ctx) => `Hello, ${ctx.spy(inputAtom)}!`)

// all updates in action processed by a smart batching
const onInput = action((ctx, event) => {
  // update the atom value by call it as a function
  inputAtom(ctx, event.currentTarget.value)
})

// global application context
const ctx = createCtx()

document
  .getElementById('name-input')
  .addEventListener('input', (event) => onInput(ctx, event))

ctx.subscribe(greetingAtom, (greeting) => {
  document.getElementById('greeting').innerText = greeting
})

Check out @reatom/core docs for detailed explanation of key principles and features.

Advanced example

Install

npm i @reatom/framework

repl

We will use @reatom/core, @reatom/npm-react, @reatom/async and @reatom/hooks packages in this example by importing it from the meta package @reatom/framework.

reatomAsync is a simple decorator which wraps your async function and adds extra actions and atoms to track creating promise statuses.

withDataAtom adds property dataAtom which subscribes to the effect results, it is like a simple cache implementation. withAbort allows to define concurrent requests abort strategy, by using ctx.controller (AbortController) from reatomAsync. withRetry and onReject handlers help to handle temporal rate limit.

Simple sleep helper (for debounce) gotten from utils package - it is a built-in microscopic lodash alternative for most popular and tiny helpers.

onUpdate is a hook which subscribes to the atom and calls passed callback on every update.

import {
  atom,
  reatomAsync,
  withAbort,
  withDataAtom,
  withRetry,
  sleep,
  onUpdate,
} from '@reatom/framework'
import { useAtom } from '@reatom/npm-react'
import * as api from './api'

const searchAtom = atom('', 'searchAtom')
const fetchIssues = reatomAsync(async (ctx, query: string) => {
  // debounce
  await sleep(250)
  const { items } = await api.fetchIssues(query, ctx.controller)
  return items
}, 'fetchIssues').pipe(
  withDataAtom([]),
  withAbort({ strategy: 'last-in-win' }),
  withRetry({
    onReject(ctx, error: any, retries) {
      return error?.message.includes('rate limit')
        ? 100 * Math.min(500, retries ** 2)
        : -1
    },
  }),
)
onUpdate(searchAtom, fetchIssues)

export default function App() {
  const [search, setSearch] = useAtom(searchAtom)
  const [issues] = useAtom(fetchIssues.dataAtom)
  const [isLoading] = useAtom(
    (ctx) =>
      ctx.spy(fetchIssues.pendingAtom) + ctx.spy(fetchIssues.retriesAtom) > 0,
  )

  return (
    <main>
      <input
        value={search}
        onChange={(e) => setSearch(e.currentTarget.value)}
        placeholder="Search"
      />
      {isLoading && 'Loading...'}
      <ul>
        {issues.map(({ title }, i) => (
          <li key={i}>{title}</li>
        ))}
      </ul>
    </main>
  )
}

The whole logic definition is only about 15 LoC, what would the count be in a different library? The most impressive thing is that the overhead is only 6KB (gzip) and you are not limited to network cache, Reatom is powerful and expressive enough for describing any kind of state.

To get maximum of Reatom and the ecosystem just go to tutorial. If you need something tiny - check out the core package docs. Also, we have a package for testing!

Roadmap

  • Finish forms package
  • Finish persist and navigation packages
  • Add adapters for most popular ui frameworks: react, angular, vue, svelte, solid.
  • Port some components logic from reakit.io, to made it fast, light and portable.
  • Add ability to made async transaction and elaborate optimistic-ui patterns and helpers / package.
  • Try to write own jsx renderer.

FAQ

Why not X?

Redux is awesome and Reatom is heavy inspired by it. Immutability, separation of computations and effects are good architecture designs principles. But there are a lot of missing features, when you trying to build something huge, or want to describe something small. Some of them is just impossible to fix, like batching, O(n) complexity or that selectors is not inspectable and breaks the atomicy. Others is really hard to improve. And boilerplate, yeah, the difference is a huge. Reatom solves all this problems and bring much more features by the almost same size.

MobX brings too big bundle to use it in a small widgets, Reatom is more universal in this case. Also, MobX has mutability and implicit reactivity, which is usefull for simple cases, but could be not obvious and hard to debug in complex cases. There is no separate thing like action / event / effect to describe some dependent effects sequences (FRP-way). There is not atomicy too.

Effector is too opinionated. There is no first-class support for lazy reactive computations and all connections are hot everytime, which is could be more predictable, but defenetly is not optimal. Effector is not friendly for fabric creation (because of it hotness), which disallow us to use atomization patterns, needed to handle immutability efficient. The bundle size is 2-3 times larger and performance is lower.

Zustand, nanostores, xstate and many other state managers have no so great combination of type inference, features, bundle size and performance, as Reatom have.

Why immutability?

Immutable data is much predictable and better for debug, than mutable states and wrapers around that. Reatom specialy designed with focus on simple debug of async chains and have a patterns to handle greate performance.

What LTS policy is used and what about bus factor?

Reatom always developed for long time usage. Our first LTS (Long Time Support) version (v1) was released in December 2019 and in 2022 we provided breaking changes less Migration guid to the new LTS (v3) version. 3 years of successful maintains is not ended, but continued in adapter package. We hope it shows and prove our responsibility.

To be honest, right now bus factor is one, @artalar - the creator and product owner of this, but it wasn't always like this as you can see. Reatom PR wasn't great in a past couple of years and a lot of APIs was experimental during development, but now with the new LST version (v3) we bring to new feature of this lib and application development experience for a long time.

How performant Reatom is?

Here is the benchmark of complex computations for different state managers. Note that Reatom by default uses immutable data structures, works in a separate context (DI-like) and keeps atomicity, which means the Reatom test checks more features, than other state manager tests. Anyway, for the middle numbers Reatom faster than MobX which is pretty impressive.

Also, check out atomization guild.

Limitations

Of course there are no software without limitations. Reatom is trying to be a silver bullet but we still have some cases witch you should know about.

  • Immutable data always have an additional performance impact and in critical cases you should think well about your structures and how you could handle it better. The good news is that you don't have to use normalization.
  • Laziness could be not obvious in some cases and will cause some updates missing. But it easy to debug a missing update, which is more explicit, than memory leaks and performance issues of hot observables. Anyway, we have hooks for hot linking.
  • Currently, there is no way to subscribe on error of any dependency, but we are working on it. In reatomAsync passed effects wraps to an error handler and allow you to handle errors, but again - you should wrap it explicit.
  • Currently, there is no asynchronous transactions support, but we are working on it. It is important feature for simplify building of optimistic UI and we really think it will improve UX a lot.
  • We have a lot of utils and the ecosystem is growing all the time, but the target of that is have a set of well done logic primitives, and there is no architecture framework or codestyle / declarative framework to fit you in one strict flow. Reatom trying to be in the middle of a library and a framework. We love procedural programming with minimum extra API and semantic overhead. Our defaults are good already to help to you to write a better code: immutability and lazyness, transactions and separation of pure computations and effects, ctx and connections and processes virtualizations.

Community

How to support the project?

https://www.patreon.com/artalar_dev

Credits

Software development in 202X is hard and we really appreciate all contributors and free software maintainers, who make our life easier. Special thanks to:

  • React, Redux and Effector for inspiration
  • microbundle for handling all bundling complexity
  • Quokka and uvu for incredible testing experience
  • TURBO for simple monorepo management
  • Astro for best in class combine of performance and developer experience
  • Vercel for free hosting and perfect CI/CD (preview branches are <3)

reatom's People

Contributors

artalar avatar belozer avatar wroud avatar allcontributors[bot] avatar mungell avatar stenin-nikita avatar whiteand avatar akiyamka avatar godested avatar pivaszbs avatar dependabot[bot] avatar ilyaryabchinski avatar ikabirov avatar bataevdaniil avatar arkatriymfalnaya avatar atassis avatar antonk52 avatar after-finitude avatar tamrazov avatar kirillku avatar nin-jin avatar xavescor avatar arswarog avatar crashmax-dev avatar vitalybaev avatar sozonov avatar binjospookie avatar vovanezha avatar yurimikushov avatar gizeasy avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.