Recoil

repository·main·Indexed 12 days ago

https://github.com/facebookexperimental/Recoil

A state management library for React that provides a high-performance way to manage shared state through atoms and selectors. It includes features such as selector cache policy configuration, snapshot persistence via the retain() API, and integration with Relay through components like RecoilRelayEnvironmentProvider and utilities like graphQLSelector.

Tokens
15.9K
Snippets
45
Records
70
Agent score
98%

What's inside Recoil

  1. Manage the todo-example project with Yarn scripts

    main

    The todo-example project is bootstrapped with Create React App and uses yarn for script execution. Use the following commands to manage the development lifecycle:

    • Development: Run yarn start to launch the app in development mode at http://localhost:3000. The page reloads on edits and displays lint errors in the console.
    • Testing: Run yarn test to launch the test runner in interactive watch mode.
    • Production Build: Run yarn build to create an optimized, minified production build in the build folder. Filenames include hashes for cache busting.
    • Eject: Run yarn eject to remove the single build dependency and copy all configuration files (webpack, Babel, ESLint, etc.) directly into your project for full customization. Warning: This is a one-way operation and cannot be undone.
    yarn start
    yarn test
    yarn build
    yarn eject
  2. Use Refine for data validation and coercion

    main

    Refine provides a suite of checkers and utilities to validate and transform data. It is organized into several categories: Primitives, Containers, and Utility checkers. You can use assertion to validate data (throwing an error on failure) or coercion to attempt to transform data into a specific type.

    Key entrypoints include:

    • assertion: Validates data against a checker.
    • coercion: Attempts to coerce data into the type defined by a checker.
    • jsonParser / jsonParserEnforced: Specialized checkers for JSON data.
    • Path: A utility to track the location of validation failures within a data structure.
    const { assertion, coercion, string, number, array, object } = require('refine');
    
    // Example usage (conceptual based on API surface):
    // assertion(string, 'hello'); // succeeds
    // assertion(string, 123);      // throws
    // const val = coercion(number, '123'); // returns 123
  3. Parameter requirements for `selectorFamily`

    main

    The parameters passed to a selectorFamily must be serializable using Recoil_stableStringify to be used as cache keys.

    Supported parameter types include:

    • Primitive: void, null, boolean, number, string
    • HasToJSON: Any object implementing a toJSON() method.
    • Array: $ReadOnlyArray<Parameter>
    • Map: $ReadOnlyMap<Parameter, Parameter>
    • Set: $ReadOnlySet<Parameter>
    • Object: $ReadOnly<{...}> (Plain objects)
  4. Understand the Loadable abstraction for async state

    main

    A Loadable is a value type that represents the state of an asynchronous operation. It is used to encapsulate whether a value is currently loading, has successfully loaded, or has encountered an error. Because Loadable is a value type, it is immutable; when the underlying request status changes, a new Loadable instance is created rather than mutating the existing one.

    A Loadable can be in one of three states:

    1. hasValue (ValueLoadable): The operation completed successfully. Use getValue() or valueMaybe() to access the data.
    2. loading (LoadingLoadable): The operation is in progress. Use promiseMaybe() or toPromise() to access the pending Promise.
    3. hasError (ErrorLoadable): The operation failed. Use errorMaybe() or errorOrThrow() to access the error object.

    You can transform a Loadable using the .map() method, which allows you to apply a function to the underlying value. If the mapping function returns a Promise, a new LoadingLoadable is returned; if it returns a new Loadable, that state is preserved.

    import { RecoilLoadable } from 'recoil';
    
    // Example of handling different states
    const handleLoadable = (loadable) => {
      if (loadable.state === 'hasValue') {
        console.log('Data:', loadable.getValue());
      } else if (loadable.state === 'loading') {
        console.log('Loading...');
      } else if (loadable.state === 'hasError') {
        console.error('Error:', loadable.errorOrThrow());
      }
    };
  5. Understand the RecoilValue type

    main

    In Recoil, a RecoilValue<T> is a union type representing either a mutable state or a read-only view of a state.

    • RecoilState<T>: Represents a piece of state that can be read from and written to.
    • RecoilValueReadOnly<T>: Represents a piece of state that can only be read (e.g., a selector or a read-only view of an atom).

    Both types share a key property of type NodeKey (a string) which uniquely identifies the node in the Recoil graph.

  6. Understand the CheckResult type in refine

    main

    In the refine library, every validation check returns a CheckResult. A CheckResult is a discriminated union that indicates whether a value matched the expected type or failed.

    • CheckFailure: Returned when a value does not match the expected type. It contains:
      • type: The literal string 'failure'.
      • message: A string describing the error.
      • path: A Path object indicating where the failure occurred.
    • CheckSuccess<V>: Returned when a value matches the expected type. It contains:
      • type: The literal string 'success'.
      • value: The validated value of type V.
      • warnings: An array of CheckFailure objects (used when options like nullWithWarningWhenInvalid are active).
  7. Use atomFamily to create parameterized atoms

    main

    An atomFamily is a function that returns a unique atom based on the input parameter provided. This is useful for creating local, private state for components where each instance needs its own atom. For example, if you pass {id: 1} to the family, you get one atom; passing {id: 2} returns a different, unique atom.

    Each unique parameter results in a unique atom key, which is internally generated using a stable stringification of the parameters.

    // Example usage pattern
    const myFamily = atomFamily({
      key: 'myFamily',
      default: (params) => params.initialValue,
    });
    
    // Returns a unique atom for each unique parameter
    const atom1 = myFamily({ id: 1, initialValue: 10 });
    const atom2 = myFamily({ id: 2, initialValue: 20 });
  8. Understand the ListenInterface in RecoilSync

    main

    The listen option in RecoilSync allows the external storage to trigger updates within Recoil. This is useful for multi-tab synchronization or server-sent events.

    ListenInterface Methods:

    • updateItem(itemKey, newValue): Updates a single item in the external storage, which in turn updates the corresponding Recoil atom.
    • updateItems(itemSnapshot): Updates multiple items at once using a full snapshot.
    • updateAllKnownItems(itemSnapshot): Updates all known items. Any item registered with the sync provider that is not present in the provided itemSnapshot will be reset to its DefaultValue.