Code Monkey home page Code Monkey logo

atomic-state's Introduction

AtomicState

CI code style: prettier Commitizen friendly bundlephobia

A decentralized state management library for React

Sometimes when you have to share some state between components you also add some complexity to it (lifting the state up, adding a context or dirtying your global state manager).

AtomicState brings to you a way to share state in a simple and decentralized way without burdening your app size and complexity.

Features Highlights

  • πŸ’‘ Simple & Reactish: Use AtomicState without learning new concepts because it works like the React API that you already know
  • πŸ’‘ Small footprint: AtomicState wieghts only 1.5Kb (gzip) on your production bundle
  • πŸ’‘ SSR ready: Server Side Rendering is a first-class citizen for AtomicState and it works like a breeze
  • πŸ’‘ Integrated DevTools: Install the official devtools from the Chrome Web Store and take a look in your atoms!
  • πŸ’‘ Decentralized: The state atoms can be loaded only when they are needed enabling you to do lazy load without troubles.

Table of contents

Quick start

Sharing some state across components sometimes is more complex than it should be.

With AtomicState it will be clean and simple:

./doYouKnowAtomicState.js

import { createStateAtom } from '@immobiliarelabs/atomic-state';

// This is an atom a container for a piece of state
export const doYouKnowAtomicState = createStateAtom({
    key: `DoYoyKnowAtomicState`, // unique ID
    default: null, // default value (aka initial value)
});

By importing the created atom you can read and modify the state wherever you want:

./DoYoyKnowAtomicStateDisclamer.js

import { useStateAtom } from '@immobiliarelabs/atomic-state';
import { doYouKnowAtomicState } from './doYouKnowAtomicState';

export function DoYoyKnowAtomicStateDisclamer() {
    // useStateAtom is like a shared version of useState
    const [answer, setAnswer] = useStateAtom(doYouKnowAtomicState);

    if (answer) {
        return null;
    }

    return (
        <div>
            Hey! Do you know AtomicState?
            <button onClick={() => setAnswer('yes')}>Yes!</button>
            <button onClick={() => setAnswer('no')}>No!</button>
        </div>
    );
}

./DoYoyKnowAtomicStateLinks.js

import { useStateAtom } from '@immobiliarelabs/atomic-state';
import { doYouKnowAtomicState } from './doYouKnowAtomicState';

export function DoYoyKnowAtomicStateLinks() {
    const [answer] = useStateAtom(doYouKnowAtomicState);

    if (answer === 'no') {
        return (
            <div>
                Oh really!?! Take a look{' '}
                <a href="https://github.com/immobiliare/atomic-state">here</a>,
                it's easy to pick up!
            </div>
        );
    }

    return null;
}

That's it and if you want to know more read the below docs!

Setup

To install the latest stable version, run the following command:

npm install @immobiliarelabs/atomic-state

Or if you're using yarn:

yarn add @immobiliarelabs/atomic-state

What is an atom?

An atom represents a piece of state. Atoms can be read from and written to from any component. Components that read the value of an atom are implicitly subscribed to that atom, so any atom updates will result in a re-render of all components subscribed to that atom:

import { createStateAtom, useStateAtom } from '@immobiliarelabs/atomic-state';

const yourNameAtom = createStateAtom({
    key: `YourName`, // unique ID
    default: '', // default value (aka initial value)
});

function TextInput() {
    // useStateAtom has the same behavior of useState
    const [yourName, setYourName] = useStateAtom(yourNameAtom);

    function handleChange(event) {
        setYourName(event.target.value);
    }

    return (
        <div>
            <label htmlFor="your-name">Your name:</label>
            <input
                id="your-name"
                type="text"
                onChange={handleChange}
                value={text}
            />
        </div>
    );
}

Deriving state

Derived atoms can be used to derive information from other atoms. They cache their output and triggers an update only when their output changes.

Conceptually, they are very similar to formulas in spreadsheets, and can't be underestimated. They help in reducing the amount of state you have to store and are highly optimized. Use them wherever possible.

import { createDerivedAtom, useAtomValue } from '@immobiliarelabs/atomic-state';
import { yourNameAtom } from './TextInput';

const yourNameIsFilledAtom = createDerivedAtom({
    key: `YourName/Filled`, // unique ID
    get(use) {
        return use(yourNameAtom) !== '';
    },
});

function TextInputFilledStatus() {
    // useAtomValue reads the state from an atom
    const filled = useAtomValue(yourNameIsFilledAtom);

    return <span>{filled ? 'Filled' : 'Empty'}</span>;
}

Effects

Atom effects are works in a similar way of React useEffect.

They have the same cleanup api and are executed only on the client side.

import { createStateAtom, useStateAtom } from '@immobiliarelabs/atomic-state';

const persistentModeAtom = createStateAtom({
    key: `PersistentMode`,
    default: true,
});

const textAtom = createStateAtom({
    key: `Text`,
    default: null,
    setup(self, { effect, get, set }) {
        /**
            `effect` lets you run effects after the atom update

            Like React.useEffect the effects are executed only in the browser after the paint
        */
        effect(
            (open) => {
                if (get(persistentModeAtom) !== true) return;

                if (get(self) === null) {
                    set(self, localStorage.getItem('LastEditedText') || '');
                } else {
                    localStorage.setItem('LastEditedText', get(self));
                }
            },
            [self]
        );
    },
});

Under the hood the atom effects are managed through React useEffect, so even in your unit tests they will behave exactly like useEffect.

Server Side Rendering

The first thing you have to do is place the AtomicStateProvider on top of your applications.

It is possible to hydrate the atoms state by passing a state object to it.

import {
    createStateAtom,
    AtomicStateProvider,
} from '@immobiliarelabs/atomic-state';
import { myFormAtom } from './atoms';

function MyApp({ formInitialState }) {
    /**
     * Every update of this value will trigger a `setState` on the related atoms
     *
     * This makes easy to update the atom values on page navigations
     */
    const atomsState = useMemo(
        () => ({
            [myFormAtom.key]: formInitialState,
        }),
        [formInitialState]
    );

    return (
        <AtomicStateProvider state={atomsState}>
            <AppCore />
        </AtomicStateProvider>
    );
}

DevTools

We have a devtools extension for Chrome

For more info take a look into the devtools docs

Powered Apps

AtomicState was created by the amazing frontend team at ImmobiliareLabs, the Tech dept at Immobiliare.it, the first real estate site in Italy.
We are currently using AtomicState in our products.

If you are using AtomicState in production drop us a message.

Support & Contribute

Made with ❀️ by ImmobiliareLabs & Contributors

We'd love for you to contribute to AtomicState! If you have any questions on how to use AtomicState, bugs and enhancement please feel free to reach out by opening a GitHub Issue.

License

AtomicState is licensed under the MIT license.
See the LICENSE file for more information.

atomic-state's People

Contributors

fefoweb avatar gdorsi avatar jellybellydev avatar semantic-release-bot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

atomic-state's Issues

The automated release is failing 🚨

🚨 The automated release from the main branch failed. 🚨

I recommend you give this issue a high priority, so other packages depending on you can benefit from your bug fixes and new features again.

You can find below the list of errors reported by semantic-release. Each one of them has to be resolved in order to automatically publish your package. I’m sure you can fix this πŸ’ͺ.

Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it.

Once all the errors are resolved, semantic-release will release your package the next time you push a commit to the main branch. You can also manually restart the failed CI job that runs semantic-release.

If you are not sure how to resolve this, here are some links that can help you:

If those don’t help, or if this issue is reporting something you think isn’t right, you can always ask the humans behind semantic-release.


No npm token specified.

An npm token must be created and set in the NPM_TOKEN environment variable on your CI environment.

Please make sure to create an npm token and to set it in the NPM_TOKEN environment variable on your CI environment. The token must allow to publish to the registry https://registry.npmjs.org/.


Good luck with your project ✨

Your semantic-release bot πŸ“¦πŸš€

[devtools] bring out @emotion's css/keyframe/global

Feature Request

For better understanding of the code it might be a good solution to bring out @emotion's css/keyframe/global declarations from the various components.

Ex: devtools/component/LogView.tsx

Q A
New Feature yes
RFC yes
BC Break no

Summary

This behavior can be seen in devtools/components/DevToolsPanel.tsx where all declarations are located upstream of the component: easy to search and possibly modify, without affecting the logic of the component itself.

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.